Autor Zpráva
gaminn
Profil *
Zdravím,
jak řašit dotaz, kdy potřebuji z tabulky vybrat záznamy, které nemají zároveň v jednom i v druhém sloupci stejné hodnoty. Např:

tabulka:
sloupec1 sloupec2
1 2
2 1
1 2

Z takové tabulky bych chtěl zmíněmým dotazem získat pouze první dva řádky, třetí chci ignorovat z toho dúvodu, že stejné hodnoty má 1. řádek.
Jan Tvrdík
Profil
Píšu to z hlavy, ale asi něco jako:

Select sloupec1, sloupec2 from tabulka WHERE sloupec1 != sloupec2 LIMIT 2
gaminn
Profil *
Ne, to nebude ono, špatně jsem se vyjádřil:

sloupec1 sloupec2
1 1 // 1. řádek
1 2 // 2. řádek
2 2 // 3. řádek
2 1 // 4. řádek
1 2 // 5. řádek - stejný jako 2.
2 1 // 6. řádek - stejný jako 4.

V tomto případě chci vybrat 1. - 4. řádek, poslední dva nechci, protože mají stejné hodnoty jako 2. resp. 4. (nejde tu ale o žádný limit, není zaručeno, že tyto záznamy budou na konci).
Peca
Profil
Distinct to asi taky nevyřeší?
gaminn
Profil *
Peca
To asi ne, jelikož požaduji unikátnost ve dvou sloupcích zároveň, to by muselo jít něco jako DISTINCT(sloupec1 AND sloupec2).
djlj
Profil
GROUP BY sloupec1, sloupec2 (hádám)
gaminn
Profil *
Ne, tohle by mělo sgrupnout podle sloupec1, následně v případě stejných hodnot ve sloupec2 podle sloupec2.
Peca
Profil
gaminn
A to snad vadí? Distinct funguje na celý záznam.
djlj
Profil
gaminn
Nebo bych v databázi nastavil unikátnost na tyhle 2 sloupce a přidal bych ještě nějaký další, ve kterém by bylo uloženo, kolikrát tam daná položka má být...
gaminn
Profil *
Peca
Jak tedy vytvořit dotaz, modifikuju-li mírně tabulku
sloupec1 sloupec2 sloupec3
1 1 1 // 1. řádek
1 2 2 // 2. řádek
2 2 3 // 3. řádek
2 1 4 // 4. řádek
1 2 5 // 5. řádek - ve sloupcích 1 a 2 stejný jako 2.
2 1 6 // 6. řádek - ve sloupcích 1 a 2 stejný jako 4.

Jde mi o stejnou věc jen s tím rozdílem, že jsem přidal sloupec3, který obsahuje nějaká data, která mě nezajímají, na jejich základě nechci zjišťovat unikátnost, ta záleží stále pouze na 1. dvou sloupcích. Data ve sloupec3 chci ale u každého záznamu stejným sql dotazem z databáze získat.
gaminn
Profil *
djlj
No víš, já to mám komplikovaný, kde to jen jde. Pokud sloupec2 obsahuje 0, potom mě unikátnost nezajímá (ale to tady teď nechci řešit, neberte to nijak v úvahu). Jen tím chci říct, že natvrdo nemohu v tabulce unikátnost nastavit pomocí UNIQUE.
Kajman_
Profil *
jak hádal djlj
... GROUP BY sloupec1, sloupec2
gaminn
Profil *
Kajman_
Aha, v tom případě jsem špatně chápal, jak postupuje GROUP BY v případě, že obsahuje více sloupců (omlouvám se djlj;)). Co kdybych ale chtěl, aby dotaz provedl to, co jsem napsal jako odpověď djlj na tento návrh (tedy, aby se záznamy seskupili podle sloupec1 a následně podle sloupec2 v již utvořených skupinách)?
gaminn
Profil *
Asi už otravuji, ale ten GROUP BY mi dává zabrat;) Proč tento zápis:

GROUP BY
IF(sloupec, (sloupec1, sloupec2), (sloupecX))

hází chybu: Operand should contain 1 column(s) . Musím tento zápis rozepsat na:

GROUP BY
IF(sloupec, (sloupec1), (sloupecX)),
IF(sloupec, (sloupec2), (sloupecX))

abych se zbavil dvou sloupců "sloupec1, sloupec2" v prvním zápisu. Opravdu to musí být takto rozepsané? Jde mi o to docílit v klauzuli GROUP BY, pokud sloupec je pravdivý, zápisu "sloupec1, sloupec2", pokud pravdivý není, tak "sloupecX".
Kajman_
Profil *
Když je divný návrh, tak často bývají i divná řešení.
gaminn
Profil *
Kajman_
Proč si myslíš, že to je špatně navržené, nikde tu snad nedávám k dispozici samotný návrh. Nebo to je možné poznat podle toho, co potřebuji provést v klauzuli GROUP BY? Obdivuji tvůj odhad... ;)

Tento GROUP BY mi alouží analogicky k tomu, k čemu slouží k tabulce, která je uvedena výše. Přepíšu-li jej na tuto tabulku (domyslete si, že má nějaký sloupec nazvaný id):
GROUP BY
IF(sloupec2, (sloupec1), (id)),
IF(sloupec2, (sloupec2), (id))

Pokud je podmínka splněna, má za úkol vytřídit duplikátní hodnoty (tak, jak jsem požadoval na začátku a jak mi poradil djlj), pokud není, nic se neseskupuje (id obsahuje vždy jedinečné hodnoty, tudíž nic seskupeno není). Rozhoduje se na základě hodnoty sloupec2. Jak už jsme řešili v mém minulém dotazu a auty a garážemi, sloupec2 má stejný význam, jako id šablony aut (obsahuje-li 0, žádná šablona není a garáž může obsahovat libovolné množství aut, není-li tam nula, garáž musí obsahovat přesně ta auta, jako jsou uvedena v šabloně). Snad jsem to napsal tak, že jsi aspoň něco pochopil...

Jinak já to v praxi používám na výpis sázkových příležitostí a událostí. Např. sázka typu 1 X 2 (typ na výhru domácích, remízu, výhru hostí) má vždy dané tři možnosti, nikdo nemůže tipovat nic jiného než jednu z těchto tří možností, takže tato sázka má nějakou šablonu, která musí být dodržena. Naproti tomu sázka typu "Kdo vstřelí gól v utkání" nemá pevné možnosti, u každého zápasu může obsahovat jiný počet možností, protože počet hráčů v různých sportech se mění, každý tým má jiný počet hráčů (počítám-li i ty na střídačce, kteří mohou nastoupit), hráči se jinak jmenují, je na mém uvážení, koho do té sázky dám..atd. Doufám, že je tam ta analogie trochu vidět.


Takže, ptám se ještě jednou - je to nutné mít v GROUP BY takto rozepsané pomocí dvou podmínek IF?
Kajman_
Profil *
je to nutné mít v GROUP BY takto rozepsané pomocí dvou podmínek IF

Může rozdělit dotaz na dva (kdy sloupec2 je nula a kdy ne) a dát mezi ně union all. Na větších datech by to mělo být rychlejší řešení než to s if.
gaminn
Profil *
Může rozdělit dotaz na dva (kdy sloupec2 je nula a kdy ne) a dát mezi ně union all. Na větších datech by to mělo být rychlejší řešení než to s if.
Vyplatí se to, i když by ty dva dotazy byly téměř identické? Můj dotaz má zhruba 40 řádků, používám v něm 4x podmínku IF právě kvůli té nule. S UNION ALL by byly oba dotazy téměř identické (2x40 řádků). Laicky vzato mi přijde, že tato verze musí být pomalejší, pokud se mají ta data vybírat dvakrát, mysql musí dvakrát projít tu samou tabulku.

Ještě jedna věc, kterou v tomto dotaze mám. Zase se to pokusím nějak vysvětlit: Mám země a v nich města, ta města mají různý status. Z tabulky chci vybrat země a města jen s některým statusem, zároveň chci ale vybrat celkový počet měst v dané zemi:

SELECT z.*, m.*, (SELECT COUNT(id) FROM mesta WHERE zeme_id = z.id)
FROM zeme z
LEFT JOIN mesta m ON m.zeme_id = z.id
WHERE m.status = X

Výsledek může vypadat nějak tato:
nazev_zeme, nazev_mesta, pocet_mest_ve_statu
ČR Brno 5
ČR Praha 5
Slovensko Bratislava 3
Rakousko Vídeň 8
Rakousko Linz 8
....................

Jde mi o to, že ten poddotaz na zjištění počtu měst ve státě se musí opakovat u každého města znova, i když jsme pořád u stejné země. Stačilo by mi, abych získal něco jako:

ČR Brno 5
ČR Praha NULL
Slovensko Bratislava 3
Rakousko Vídeň 8
Rakousko Linz NULL
....................

Dá se nějak zajistit, aby se ten poddotaz provedl jen tolikrát, kolik to je nutné - tedy jenom jednou u každé země?
Kajman_
Profil *
Vyplatí se to, i když by ty dva dotazy byly téměř identické?
Zkuste si to změřit. Náročnost dotazů není o počtu řádků.


SELECT z.*, m.*, p.mest
FROM (SELECT COUNT(id) mest, zeme_id FROM mesta group by zeme_id) p
RIGHT JOIN zeme z ON p.zeme_id=z.id
LEFT JOIN mesta m ON m.zeme_id = z.id
WHERE m.status = X
gaminn
Profil *
Zkuste si to změřit. Náročnost dotazů není o počtu řádků.
Zkusil jsem - opravdu, při naplnění tabulky více daty je UNION čím dál tím rychlejší. Pro starší dotaz jsem v PHPMyAdmin dostával časy 1,03s, pro UNION 0,95s. Nedalo mi to a ještě jsem časy změřil přímo v PHP skriptu. Tady je rozdíl úplně propastný - dotaz s IF trvá stále 1,03s, ale dotaz s UNION jenom 0,0025s.

Jak je vůbec možné, že je mezi PHPMyAdminem a mým měřením takový rozdíl? V měření chybu nedělám:

function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}

$time_start = getmicrotime();
// dotaz
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo $time;

Trochu mi to vrtá hlavou;)
Kajman_
Profil *
Takový skok bude způsoben asi díky cache.
Toto téma je uzamčeno. Odpověď nelze zaslat.