

SQL dotaz
Nedaří se mi už delší dobu zkonstruovat dotaz.
Mám tabulku, která má několik sloupců.
A já chci vytáhnout všechny záznamy tak, aby podle jednoho konkrétního sloupce nebyly duplicity.
Na to lze použít distinct, ale nefungoval tak, jak jsem ho použil:
SELECT distinct (entry_state), address_book_id, entry_company FROM address_book group by entry_state WHERE entry_state NOT LIKE ' ' ORDER BY entry_company
bohužel distinct takto jednoduše nelze použít, protože v ostatních sloupcích jsou duplicity žádoucí.
Další nápad mám:
SELECT * FROM address_book WHERE entry_state NOT LIKE ' ' in (select entry_state FROM address_book GROUP BY entry_state HAVING count(entry_state)>1))
Hlasi chybu
A navíc si uvědomuji, že tímto způsobem by se duplicity nezobrazili ani jednou a já chci duplicity zobrazit (ale jen 1x)
za prve, group by nemoze byt pouzite pred where ....
jednotlive klauzuly maju svoje poradie:
1. where
2. group by
3. having
4. order by
za druhe:
distinct robi to, ze ti zrusi duplicity konkretnych riadkov ako takych cize sa musia hodnoty zhodovat vo vsetkych zobrazovanych stlpcoch.
za tretie:
co tym chces dosiahnut? nejaky priklad dat by bodol. Lebo z tohto mam trochu dojem, ze hasis blbym dotazom este vacsiu blbost v datovom modeli.
inak ak chces zrusi duplicitu podla nejakeho stlpca a v ostatnych stlpcoch ti je jedno aka hodnota bude v ramci danej skupiny, tak takto:
select pole1, max(pole2), max(pole3), max(polex) from tabulka group by pole1;
pripadne:
select pole1, group_concat(pole2), group_concat(pole2), ... from tabulka group by pole1;
inak ten dotaz, ktory je tucnym je za prve syntakticky uplne zle a logicky totalna blbost.
select pole1, max(pole2), max(pole3), max(polex) from tabulka group by pole1;
Dá se použít funkce max na řetězce?
Nemůžu to teď vyzkoušet.
Tabulka se jmenuje address_book a má tyto sloupce:
address_book_id - jedinečné id
entry_state - text email
entry_company - text popis
A i když to vypadá kuriózně, některé firmy jsou zaregistrovány vícekrát pod stejným mailem, ale s trochu odlišným názvem.
No a potřebuju vytáhnout všechny maily takto:
SELECT distinct entry_state FROM address_book
Nicméně chci ke každému vytaženému mailu znát i address_book_id a entry_company, což uvedený dotaz pochopitelně nedělá.
ano, funkcia max ide pouzit aj na datumy aj na retazce. treba ale brat do uvahy, ze k danemu emailu dostanes vzdy len jeden udaj z danej skupiny.
preto je asi jedina moznost ten group_concat.
dostanes jeden riadok s danym mailom a k nemu v druhych stlpcoch vsetky hodnoty patriace danemu mailu oddelene ciarkou.
inak je to cele dost nezmyselne, lebo chces z niekolkych riadkov, ktore sa zhoduju len v jednom stlpci urobit 1 riadok. kam sa maju podiet tie ostatne hodnoty v stlpcoch z dalsich riadkov?
a co ak mas 3 riadky s mailom abc@abc.sk?
ktore address_book_id k nemu chces vytiahnut? z riadku c.1, alebo c.2 pripadne c.3? ak ktorekolvek, tak pouzi to max (pripadne min), ak vsetky, tak jedine group_concat. distinct je v tomto pripade uplne nanic. to by bolo dobre iba ak by si mal napriklad 2 rovnake riadky.
To je v pohodě.
Takže je šumafuck, který z duplicitních popisů se přiřadí k adrese. Důležité jen je, aby každý vytažený řádek z db měl jiný email.
Duplikace vznikly historicky tím, že se někdo netrpělivý registroval vícekrát a nezapamatoval si přesně co napsal předtím do popisu, a napsal to binárně jinak.
Zítra to vyzkouším, teď jdu spát.
daj si na entry_state unique index a uz sa nepodari vlozit 2 riadky s rovnakym mailom
Díky, funguje.
Ještě bych se chtěl zeptat, jaktože tu funkci max v tom dotazu vlastně používám na ostatní sloupce, když cílem je unikátní právě ten první sloupec.
Chtěl bych tomu rozumět.
Respektive co v tom dotazu se stará o to, aby vypadly shodné záznamy v prvním poli.
max je agregacna funkcia, rovnako ako min, avg, sum a podobne. cize z nejakej skupiny riadkov vyberie maximalnu hodnotu z daneho stlpca. kedze ale v selecte je este group by na stlpec s mailom, tak vyberie vzdy maximalnu hodnotu pre urcenu skupinu mailov.
priklad: mas tabulku T1 a v nej stlpec mail a cislo. v tabulke su 4 riadky nasledovne:
abc@abc.sk | 1
abc@abc.sk | 2
dfe@dfe.sk | 3
dfe@dfe.sk | 4
ak by som spravil select
select max(cislo) from t1;
vrati mi to len 4
ak ale dam select mail, max(cislo) from t1 group by mail;
vrati mi to
abc@abc.sk | 2
dfe@dfe.sk | 4
Inak napadol ma este jeden select pre to tvoje riesenie a to take, ze by vratil vzdy posledny registrovany riadok pre kazdy mail:
select address_book_id, entry_company, entry_state from address_book where address_book_id in (select max(address_book_id) from address_book group by entry_state);
Jjj. Zkusil jsem tam vynechat funkci max a funguje to i bez ní.
Není tam tedy použítí max zbytečné?
kde si vynechal tu funkciu max? Bez nej to ist urcite nemoze.
A přece se točí.
Vypadá to takhle:
SELECT entry_state,address_book_id as address_book_id, entry_company as entry_company FROM address_book WHERE entry_state NOT LIKE ' 'group by entry_state ORDER BY entry_company
No mas pravdu, teraz som si to vyskusal narychlo nasimulovat. Vyzera, ze to da do tych dalsich poli vzdy hodnoty z prveho riadku pre ten dany mail.
MySQL vie niekedy prekvapit, ale na 100% mozem povedat, ze Oracle alebo MS SQL by pri tomto zapise vyhlasil chybu, ze one 2 polia nie su agregovane nejakou agregacnou funkciou. Chlapci z MySQL si to ale asi spravili po svojom. Ale co cakat, ked je to zadarmo.
na okraj, nepouzivaj not like, na vyhodnocovanie je dost pomaly. Radsej daj entry_state <> ''