Autor Zpráva
Jcas
Profil *
Použiji takovou svou terminologii:
Levá tabulka(LT) JOIN pravá tabulka(PT) (nalevo od JOIN a napravo od JOIN)

1. Příklad 1
V levé tabulce (Petr, Pavel) jsou 2 záznamy. V pravé je jich 4 (kouří, pije, zahýbá, krade).
Petr - kouří, pije, krade
Pavel - pouze zahýbá.
Vyber vše z `LT` JOIN `PT` - vrátí pouze 2 záznamy, s tím že Petrovi přiřadí první nalezenou hodnotu. ( vlevé tabulce jsou pouze 2 hodnoty)

A když to zrcadlově prohodím. LT za PT (vybírám 4 řádky z tabulky a k nim přiřadím jméno), tak výsledkem budou 4 hodnoty a tím získám potřebný výsledek. Petr - kouří, pije, krade a Pavel - pouze zahýbá.

2. Příklad
Nyní schválně vynechám hodnoty NULL.
Vyber vše z `LT` LEFT JOIN `PT` -vrátí 4 hodnoty.
Pokud v pravé tabulce existuje více záznamů, tak se vyberou také.
Hodnota z levé tabulky se zopakuje.
Tedy:
-Petr - kouří
-Petr - pije
-Petr - krade
-Petr - zahýbá


3. Příklad
Ty nuly asi chápu dobře.
Pokud do levé tabulky přidáme Michala, který je naprosto slušný, Tak výsledkem bude 5 řádků. A ten 5. bude.
- Michal - null

4. Příklad - Spojení více jak dvou tabulek. Vytvoříme třetí tabulku `co`.
Krade (auta, prachy), pije (pivo, vodu), zahýbá (za roh), kouří (trávu)
Našel jsem syntaxi, Která je:
JOIN....ON....
JOIN....ON....
JOIN....ON....

Při vytahování dat se používá while, kdy dotaz vrátí záznam a pak se snaží najít další, když ho najde, tak cyklus while pokračuje, když ne, tak se ukončí.
Lze tedy říci, že toto napojení JOIN na sebe se chová stejně jako while?

While(je vrácen záznam){   //Petr pije, při dalším průběhu cyklu Petr - krade, a při 3. kouří
   while(je vrácen záznam) {   //pije pivo - při druhém průběhu - pije vodu, a při 3. trávu
       while(je další záznam) {   //kdybych přidal další tabulku - pivo-bernard
      }
   }   
}

A jak postupně nenachází záznamy, tak jeden cyklus za druhým končí.

Co mi ale není jasné, je podmínka WHERE na konci. ta se musí stahovat na všechny JOIN? Nebo se vztahuje pouze k prvnímu?
Kcko
Profil
Jcas:
Sorry, nemám část tvůj sloh, ale vizuálně Ti pomůže tento obrázek
Alphard
Profil
K tomu where, aplikuje se na spojení všech tabulek, kdy (před vyfiltrováním v klauzuli join on) vzniká kartézský součin – tedy vzájemné kombinace všech záznamů ve spojovaných tabulkách. Takže se běžné kombinují sloupce různých tabulek where tabA.sloupec = 1 and tabB.sloupec = 2.
Snad jste se ptal na tohle, nejsem si z toho dotazu úplně jistý.
juriad
Profil
A co kdyby sis to zkusil? http://sqlfiddle.com/#!2/cc21d/4

JOIN vždy porovná každou hodnotu v první tabulce s každou hodnotou v druhé tabulce a ponechá jen takové záznamy, které splňují vazební podmínku.
Z toho vyplývá, že JOIN je nezávislý na pořadí tabulek. Nic jako „vybere první“ v SQL neexistuje (podle standardu), k tomu bys musel použít nějakou agregační funkci. Dotaz vždy vybere všechny možnosti, které splňují podmínky.

Tedy 1. příklad vrátí v každém případě 4 záznamy.

Pokud použiješ LEFT JOIN či RIGHT JOIN, tam už závisí na pořádí tabulek. Doporučuji vždy používat LEFT JOIN a na variantu RIGHT zapomenout. Jak jsem povídal, že databáze zkusí porovnat každý s každým, tak v případě LEFT JOINu, pokud pro záznam v levé tabulce nenalezne žádný záznam v pravé, přesto jej vrátí (sloupce odpovídající těm z pravé tabulky budou NULL).

Tedy 2. příklad se bude chovat úplně stejně jako 1, protože pro každého člověka existuje alespoň jedna neřest.

3. příklad
Ale pokud bys přidal Michala, který nemá žádnou neřest, tak by jej dotaz s JOINem nevrátil vůbec (neexistuje neřest, kterou by měl), ale dotaz s LEFT JOINem ano (neřest je nahrazena NULLy).

Jelikož přílíš nezáleží na pořadí JOINovaných tabulek, je logické, že je můžeš JOINovat, jak se ti zlíbí.
Pokud začneš používat LEFT JOIN, na pořadí začne záležet, ale stále si jakoby můžeš JOINy uzávorkovat jak chceš (operace je asociativní).


Kdysi dávno JOIN neexistoval a vše se dělalo jen pomocí čárky (má význam spojení všeho se vším):
SELECT * FROM leva, prava WHERE leva.col1 = prava.col2 AND leva.col3 = 42
„Zkus všechny možnosti pro záznamy z tabulky leva a prava. Ponechej jen takové dvojice, pro které platí podmínka...“

Pak se přišlo na to, že se v podmínce WHERE motají podmínky dvou typů:
1) podmínka na vazbu (co musí platit mezi tabulkami)
2) podmínka na filtrovanou hodnotu (podmínka s konstantou)
Může se zdát, že podmínek je málo, ale v praxi se ti jich může sejít třeba deset. Proto se navrhl systém JOINů, aby se dotaz zpřehlednil:
SELECT * FROM leva JOIN prava ON leva.col1 = prava.col2 WHERE leva.col3 = 42
Na první pohled je vidět, co musí platit mezi tabulkami a jaká je podmínka na filtrování. Přesto je to do puntíku stále to samé, jen jinak zapsané.


Jak jsem ukázal na příkladu v sqlfidlu, i v tom jednoduchém příkladě potřebuješ tři tabulky, protože člověk může mít více neřestí a naopak jednu neřest může mít více lidí. Jde o vztah M-ku-N.

Pokud bys chtěl přidat další vlastnost co (co-pije, co-krade, ...), tak jde o ternární vazbu (ta prostřední tabulka se odkazuje na tři tabulky, nikoli jen na dvě). Ale to vůbec nic nemění na tom, že prostě přidáš ještě jeden JOIN. V klauzuli FROM může být libovolné množství tabulek propojených JOINem, klauzule WHERE se týká filtrování.

Pokud bys chtěl nějaký netriviální příklad s více JOINy, tak zkus najít dvojici lidí, kteří mají stejnou neřest a zároveň jeden z nich kouří (poslední část bude zvýrazněná).
SELECT u1.name name1, u2.name name2, h.habit
FROM users u1
JOIN user_habits uh1 ON u1.id = uh1.user_id
JOIN user_habits uh2 ON uh1.habit_id = uh2.habit_id
JOIN users u2 ON uh2.user_id = u2.id
JOIN habits h ON uh1.habit_id = h.id # nebo ekvivalentně uh2.habit_id = h.id
JOIN uh3 ON u1.id = uh3.user_id
WHERE uh3.habit_id = 1 # alternativně: JOIN habits h2 ON h2.id = uh3.habit_id WHERE h2.habit = 'kouří'

V tom dotazu name1, name2, uh1, uh2, u1, u2, h jsou aliasy (pojmenování sloupce či tabulky, aby se autor neupsal k smrti). Volitelně je před ně možné napsat AS:
SELECT u1.name AS name1 ... FROM users1 AS u1

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