Autor Zpráva
KeFyr
Profil
Ahoj,

řeším sql dotaz pro výběr dat a nějak s tím nemohu pohnout. Zkoušel jsem řešit skrze GROUP BY a DISTINCT i různě kombinovat řazení a WHERE, ale nepovedlo se mi dosáhnout výsledku.

Mám například strukturu tabulky:

| uniqueID | userID | username | points | datetime |
| 1 | 1 | Pepa | 1 | 2020-01-11 11:11:11 |
| 2 | 2 | Martin | 1 | 2020-01-11 11:11:11 |
| 3 | 3 | Libor | 1 | 2020-01-11 11:11:11 |
| 4 | 1 | Pepa | 2 | 2020-02-10 22:22:22 |
| 5 | 2 | Martin | 3 | 2020-02-10 22:22:22 |
| 6 | 3 | Libor | 2 | 2020-02-10 22:22:22 |

A já potřebuji udělat SELECT (uniqueID: 4, 5, 6), který vybere VŽDY poslední řádek od každého userID (zpracovávám přes foreach() v PHP), řazeno podle datetime od nejnovějšího. Pokud poskládám nějaký SELECT dokážu z toho vytáhnout sice data, ale nikoliv od nejnovějšího datetime ale nejstaršího. Na zahraničních fórech jsem se při použití GROUP BY dočetl něco o agregaci, ale to už jsem úplně v koncích.

Databázím moc nerozumím, mohl by mi prosím někdo ukázat dotaz a stručně vysvětlit jak funguje?
Tomášeek
Profil
KeFyr:
Nemělo by to být něco jako GROUP BY userID ORDER BY datetime DESC?
KeFyr
Profil
Tomášeek [#2]: to jsem si původně myslel také, ale vyplivne místo řádku č.4 řádek č.1 a za boha netuším proč.

Tabulka s daty:


SQL dotaz + výsledek selectu:
Tomášeek
Profil
KeFyr:
Hm, nejsem úplně databázista, tak se omlouvám za předchozí tip, ale co takhle? Vrátilo mi to správný výsledek, rychlost si zkus změřit. Nebo počkej, až se objeví někdo, kdo se vyzná více :-)


SELECT * 
FROM t 
WHERE uniqueID IN (
    SELECT MAX(uniqueID) 
    FROM t 
    GROUP BY userID 
)
Keeehi
Profil
KeFyr:
Potřebovali bychom vědět, zda databáze podporuje windowing funkce. Pokud ano, bude řešení celkem jednoduché. Pokud to nevíš, tak nám řekni její přesnou vriantu (mariadb/mysql a celé číslo verze)

Pokud je neumí, je tu pak několik možností řešení. V poddotazu udělat GROUP BY userID a vybrat buď max(uniqueID) nebo max(datetime). U uniqueID je nutno předpokládat, že fyzicky záznamy s větším id mají i novější datetime. Pokud toto nemusí platit, pak bude potřeba použít datetime, což znamená jeden poddotaz navíc (nebo join). Navíc ještě bude potřeba řešit situaci, kdy datetime bude duplicitní pro nějakého uživatele.
Pak je tu ještě tato varianta. Vypadá to, že chceš archivovat nějaké hodnoty pro uživatele, jinak řečeno zachytit vývoj počtu jeho bodů v čase. To co máš teď ty, tomu se u datových skladů říká SDC2. Existují ale i více verzí. Tvoje základní, prostě přidává nové záznamy a někde si udržuje informaci o jejich pořadí. V tvém případě to je sloupec datetime. Jiné verze přidávají další sloupec, podle kterého dokáží rychle určit, který záznam je právě aktuální a který není. Může jít jednoduchý flag true/false, který rozliší platné a staré záznamy, nebo trochu sofistikovanější timestamp s koncem platnosti toho záznamu. Je tam ale trochu složitější, když se přidávají nové záznamy. Je totiž potřeba ten poslední co byl až do teď aktuální upravit a zneplatnit.
KeFyr
Profil
Tomášeek [#4]:

Zatím nasazeno, děkuji.

Keeehi [#5]:

Mnohokrát děkuji za vyčerpávající odpověď. Během volna se budu celému věnovat do hloubky abych toto celé pochopil a uměl do budoucna použít a případně se ještě optám v tomto threadu!

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0