MySQL - podmíněný SELECT přes dvě tabulky

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #75 kdy: 12. 10. 2019, 09:45:39 »
To, co říká Filip, dělá spousta lidí - podmínku zaměňuje s joinovacím kritériem.
Ano, jedním z nich je například Miroslav Šilhavý, který se neustále spojovací kritérium snaží cpát do podmínek.


Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #76 kdy: 12. 10. 2019, 09:51:27 »
Ano, jedním z nich je například Miroslav Šilhavý, který se neustále spojovací kritérium snaží cpát do podmínek.

Spojovací kritérium je odvislé od struktury dat. Tu nám tazatel popsal. V tbl2 mohou a nemusí být záznamy odpovídající tbl1. To je spojovací kritérium. Toto spojovací kritérium zůstane platné za všech okolností, i když se podmínka dotazu změní.

S tímto spojením pak můžete pokládat dotaz, který tazatel položil (najít záznamy, které mají odpovídající záznam v tbl2 a zároveň allowed > 0), ale můžete podmínku i libovolně přeformulovat (zejm. najít záznamy, které nemají odpovídající záznam v tbl2 nebo mají allowed = 0). S vaším inner joinem se můžete jít klouzat, při změně podmínky budete muset přeformulovat i joiny.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #77 kdy: 12. 10. 2019, 09:52:31 »
Filip! v prvej otazke tohoto threadu bolo spomenute ze:
1. mas tabulku 1 s ID
2. mas tabulku 2 kde su niektore ID s tabulky 1
preto LEFT JOIN... tam neni o com s inner joinom.
Prosím, neopakujte znovu chyby, které už tu byly dávno vysvětlené. To, co jste napsal vy, je velmi nepřesný přepis původního dotazu. Z původního dotazu totiž nebylo zřejmé, jak se má s neexistujícími záznamy z druhé tabulky zacházet. Proto jsem se na to zeptal, a Racchek na to odpověděl – ve výsledné sadě mají být jen ty prvky, které mají záznam v druhé tabulce (a ten samozřejmě má správnou hodnotu). Sémanticky se tedy jedná o INNER JOIN. Druhá věc je, jestli ho napíšete normálně jako INNER JOIN, nebo – pokud máte averzi na INNER JOINy jako Miroslav Šilhavý – ho klidně můžete napsat jako CROSS JOIN a všechny podmínky dát do WHERE, aby to bylo dostatečně obecné.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #78 kdy: 12. 10. 2019, 10:04:35 »
klidně můžete napsat jako CROSS JOIN a všechny podmínky dát do WHERE, aby to bylo dostatečně obecné.

JOINY mají odpovídat struktuře dat, nikoliv podmínkám dotazu. CROSS JOIN by těmto datům neodpovídal, proto by byl taky špatně. Kritéria spojení byste přesouval do podmínky dotazu.

Stejně tak špatně by bylo dávat i druhou podmínku do joinu, byť by to fungovalo:
SELECT * FROM tbl1 JOIN tbl2 ON (tbl1.id_data=tbl2.id_data AND allowed > 0)

V tomto případě byste se mohl WHERE vyhnout úplně a je to ta samá chyba - přesouvání podmínky dotazu do kritérií spojení.

Prostě Váš návyk omezovat joiny podle podmínky dotazu je nezdravý, tak se SQL dělat nemá. Na projektu, kde se musí nad dotazem (nebo view) vystřídat víc lidí, nebo je použitý ve více situacích, nebo se může podmínka dotazu měnit, je potřeba dodržovat určitá pravidla.

Umím pochopit, že jste se třeba ještě nedostal do prostředí, kde by byly takové nároky, ale pak si aspoň nechte poradit a nešiřte bludy.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #79 kdy: 12. 10. 2019, 10:05:21 »
Spojovací kritérium je odvislé od struktury dat.
Není. Spojovací kritérium je závislé na významu dat. Autoři standardu SQL opravdu nebyli tak hloupí, aby vytvořili dva různé příkazy (INNER JOIN a OUTER JOIN), které by z hlediska implementace byly identické, pouze by odkazovaly na (nevýznamnou) strukturu databáze. Navíc by jejich rozlišení databáze stejně nedokázala nijak zkontrolovat, takže byste je ve spoustě případů měl špatně.

Tu nám tazatel popsal. V tbl2 mohou a nemusí být záznamy odpovídající tbl1. To je spojovací kritérium.
Nikoli, tazatel napsal, že ve výsledné sadě mají být jen ty záznamy, které mají v tbl2 záznam. To je spojovací kritérium.
ium zůstane platné za všech okolností, i když se podmínka dotazu změní.

S tímto spojením pak můžete pokládat dotaz, který tazatel položil (najít záznamy, které mají odpovídající záznam v tbl2 a zároveň allowed > 0)
Jenže tazatel položil jiný dotaz. Velda se tady o tom diskuse, klidně se vraťte na začátek tématu a ten dotaz si znovu přečtěte. Tazatel napsal „z tbl1.id_data vybrat pouze to, co v tbl2 je jako allowed >0“. První odpovídající to pochopili tak, jak to tazatel myslel – záznamy neexistující v tbl2 se vůbec neberou v úvahu, protože ani nebudou výsledkem spojení těch dvou tabulek, a podmínkou pro zobrazení ve výsledné sadě je tbl2.allowed > 0.

S vaším inner joinem se můžete jít klouzat, při změně podmínky budete muset přeformulovat i joiny.
Kdyby jenom JOINy, se změnou podmínky budete muset často připojit jiné tabulky… S tím vaším přístupem, kdy chcete mít univerzální dotaz na všechno, ve kterém budete jenom měnit podmínky, byste měl udělat CROSS JOIN všech tabulek v databázi a pak si v podmínkách poskládat, co zrovna potřebujete.


Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #80 kdy: 12. 10. 2019, 10:08:51 »
JOINY mají odpovídat struktuře dat, nikoliv podmínkám dotazu. CROSS JOIN by těmto datům neodpovídal, proto by byl
taky špatně. Kritéria spojení byste přesouval do podmínky dotazu.
Ano, a tady je struktura dat taková, že se zabýváme jenom záznamy existujícími v tbl2. Existence záznamu není podmínkou dotazu, protože takové záznamy se do výsledné sady před filtrováním vůbec nedostanou. Ostatně tazatel o tom přesně takhle uvažoval, proto dokonce to spojování tabulek ani nezmínil – připadalo mu to samozřejmé.

Prostě Váš návyk omezovat joiny podle podmínky dotazu je nezdravý, tak se SQL dělat nemá.
Ale já to tak nedělám. To jenom vy jste pořád nepochopil, jaká je struktura dat.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #81 kdy: 12. 10. 2019, 10:15:59 »
Ano, a tady je struktura dat taková, že se zabýváme jenom záznamy existujícími v tbl2.

Ne. Struktura dat je dána databází (její zamýšlenou interpretací). Struktura se nemění dotaz od dotazu. Ve správném návrhu by měla být vyjádřena i správně postavenými FOREIGN KEYS.

Existence záznamu není podmínkou dotazu, protože takové záznamy se do výsledné sady před filtrováním vůbec nedostanou. Ostatně tazatel o tom přesně takhle uvažoval, proto dokonce to spojování tabulek ani nezmínil – připadalo mu to samozřejmé.

Existence záznamu je tacitní podmínkou dotazu. Pokud musí existovat allowed > 0, implikuje to existenci záznamu v tbl2.

Vy jste mu zodpovědel dotaz jen pro jeho jeden speciální případ, ale už jste vůbec nepřemýšlel, že v praxi se podmínky parametrizují. Panu kolegovi, který se učí, a který potřebuje vytvořit správné návyky, jste poradil pěknou blbost, která mu jednou zkomplikuje život.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #82 kdy: 12. 10. 2019, 10:23:14 »
Kdyby jenom JOINy, se změnou podmínky budete muset často připojit jiné tabulky… S tím vaším přístupem, kdy chcete mít univerzální dotaz na všechno, ve kterém budete jenom měnit podmínky, byste měl udělat CROSS JOIN všech tabulek v databázi a pak si v podmínkách poskládat, co zrovna potřebujete.

Na dotaz tazatele by navrátilo identické záznamy:
SELECT * FROM tbl1 INNER JOIN tbl2 USING (id_data) WHERE allowed > 0
SELECT * FROM tbl1 LEFT OUTER JOIN tbl2 USING (id_data) WHERE allowed > 0
SELECT * FROM tbl1 INNER JOIN tbl2 ON (tbl1.id_data=tbl2.id_data AND allowed > 0)
SELECT * FROM tbl1 CROSS JOIN tbl2 WHERE tbl1.id_data=tbl2.id_data AND allowed > 0
SELECT * FROM tbl1, tbl2 WHERE tbl1.id_data=tbl2.id_data AND allowed > 0
SELECT * FROM tbl1 FULL OUTER JOIN tbl2 ON (tbl1.id_data=tbl2.id_data) WHERE allowed > 0
SELECT * FROM tbl1 FULL OUTER JOIN tbl2 ON (tbl1.id_data=tbl2.id_data AND allowed > 0)
SELECT * FROM tbl1 INNER JOIN tbl2 ON (true) WHERE tbl1.id_data=tbl2.id_data AND allowed > 0

Pouze ale jeden z těchto dotazů je sémanticky správně.

(Uvědomuji si, že MySQL nezná FULL OUTER JOIN, uvedl jsem jen pro pořádek a pro ty, co používají nějakou rozumnější databázi.)


Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #83 kdy: 12. 10. 2019, 11:21:39 »
Ne. Struktura dat je dána databází (její zamýšlenou interpretací). Struktura se nemění dotaz od dotazu. Ve správném návrhu by měla být vyjádřena i správně postavenými FOREIGN KEYS.
Opakuji ještě jednou – tady je struktura dat taková, že se zabýváme jenom záznamy existujícími v tbl2.

Existence záznamu je tacitní podmínkou dotazu. Pokud musí existovat allowed > 0, implikuje to existenci záznamu v tbl2.
Děláte přesně to, před čím jste varoval – snažíte se JOIN převádět na WHERE. Tyhle tacitní podmínky právě popisují způsob spojování tabulek. Proto se v SQL dotazu píšou zvlášť a je na ně speciální syntaxe – JOIN.


Vy jste mu zodpovědel dotaz jen pro jeho jeden speciální případ, ale už jste vůbec nepřemýšlel, že v praxi se podmínky parametrizují.
Právě naopak, já jsem popsal takový dotaz, kde jsou ve WHERE všechny podmínky a není tam nic jiného, než podmínky. Ty si může tazatel parametrizovat a upravovat jak je libo, a nemusí pořád myslet na to, že tam musí přidávat ještě spojovací podmínku – protože tu má správně uvedenou u JOINu.

Panu kolegovi, který se učí, a který potřebuje vytvořit správné návyky, jste poradil pěknou blbost, která mu jednou zkomplikuje život.
Nezlobte se na mne, ale blbosti tu píšete vy. Neustále naznačujete, že INNER JOIN by se měl používat jenom tam, kde obě tabulky obsahují identickou sadu entit, akorát ke každé jedné entitě nesou jinou sadu vlastností. Že se INNER JOIN vůbec nemá implementačně lišit od OUTER JOINu, nýbrž že je to jenom komentář pro databázového specialistu, který mu říká „obě tabulky mají stejný počet záznamů, které si navzájem odpovídají“, resp. „vlastně by to měla být jen jedna tabulka, ale z nějakého důvodu je rozdělená na dvě“. V obou tabulkách by tedy mělo být nastavené FOREIGN KEY na tu druhou tabulku. Pokud by byl INNER JOIN přes více tabulek, muselo by to platit pro všechny a FOREIGN KEY by zřejmě měly mít každá s každou.

Pak by mne ale zajímalo, jak odůvodníte, proč jsou ty záznamy ve více tabulkách, proč to není jedna tabulka.

Pouze ale jeden z těchto dotazů je sémanticky správně.
Ano, ten první. Všimněte si, že je to přesný přepis zadání: „z tbl1.id_data vybrat pouze to, co v tbl2 je jako allowed >0“. Když si tu českou větu přeložíte do angličtiny, máte už ten SQL dotaz vlastně hotový.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #84 kdy: 12. 10. 2019, 11:41:22 »
Opakuji ještě jednou – tady je struktura dat taková, že se zabýváme jenom záznamy existujícími v tbl2.

Asi to neumím napsat, abyste mě pochopil. Nemyslím strukturu dotazu, ale strukturu databáze. Ta byla popsána tak, že v tbl2 může a nemusí záznam existovat.

Neustále naznačujete, že INNER JOIN by se měl používat jenom tam, kde obě tabulky obsahují identickou sadu entit, akorát ke každé jedné entitě nesou jinou sadu vlastností. Že se INNER JOIN vůbec nemá implementačně lišit od OUTER JOINu, nýbrž že je to jenom komentář pro databázového specialistu, který mu říká „obě tabulky mají stejný počet záznamů, které si navzájem odpovídají“, resp. „vlastně by to měla být jen jedna tabulka, ale z nějakého důvodu je rozdělená na dvě“. V obou tabulkách by tedy mělo být nastavené FOREIGN KEY na tu druhou tabulku. Pokud by byl INNER JOIN přes více tabulek, muselo by to platit pro všechny a FOREIGN KEY by zřejmě měly mít každá s každou.

Jsou situace, kdy máte obecně definováno, že záznam musí existovat. Např. na dokladu uvedený odběratel (tabulka odběratelů však slouží více účelům), nebo vazba na číselníky (opět využívané z více míst). Tam je INNER JOIN na místě.

----

Pokud tedy tazatel napsal, že v tbl2 nemusí záznam být - pak je tato skutečnost nějak významná (něco vyjadřuje). Pokud tento stav zakryjete INNER JOINEM, můžete zaplakat nad výdělkem. Bohatě stačí, aby chtěl Racchek vybrat záznamy které mají allowed=0 NEBO nemají odpovídající záznam, a už je v háji a bude přepisovat nejen podmínku, ale i JOINY.

SQL je velmi chytře navržené, ne nadarmo jsou HAVING, WHERE a ORDER BY až na konci - v nich se máte rejpat. Co je nad nimi má být co nejvíc zobecněné.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #85 kdy: 12. 10. 2019, 12:21:36 »
Asi to neumím napsat, abyste mě pochopil. Nemyslím strukturu dotazu, ale strukturu databáze. Ta byla popsána tak, že v tbl2 může a nemusí záznam existovat.
Já to chápu, problém vidím spíš v tom, že píšete obecně o jakési struktuře databáze, ale nenapsal jste, co konkrétně to znamená. Jak mají vypadat tabulky, jaké na nich mají být FOREIGN KEYS nebo jiná omezení?

Navíc to pokládám za nesmyslné, SELECT popisuje výsledná data, ne strukturu databáze. Může dávat smysl nad jednou dvojicí tabulek dělat INNER JOIN i OUTER JOIN, protože to má pokaždé jiný význam – i když struktura tabulek bude pořád stejná.

Jsou situace, kdy máte obecně definováno, že záznam musí existovat. Např. na dokladu uvedený odběratel (tabulka odběratelů však slouží více účelům), nebo vazba na číselníky (opět využívané z více míst). Tam je INNER JOIN na místě.
Nezapomněl jste na to, že INNER JOIN je symetrický a nerozlišuje levou a pravou tabulku? Co kdyby tazatel přeformuloval svůj požadavek na: „Chci všechny záznamy z tbl2, které mají allowed > 0, a k nim připojit odpovídající záznam z tbl1. Pro každý záznam z tbl2 existuje záznam v tbl1.“ Struktura tabulek zůstává stejná. Výsledná sada záznamů zůstává stejná. Množiny správných SQL dotazů pro obě varianty formulace zadání jsou identické. Jenom podle vašich pravidel je najednou správně INNER JOIN. Přitom zároveň tvrdíte, že rozhodnutí, zda INNER nebo OUTER JOIN závisí na struktuře tabulek, ne na sémantice dotazu (myslím toho formulovaného přirozeným jazykem, ne SQL).

Pokud tedy tazatel napsal, že v tbl2 nemusí záznam být - pak je tato skutečnost nějak významná (něco vyjadřuje).
Pokud by ta skutečnost byla významná, napsal by explicitně, jak se má zacházet s neexistujícími záznamy v tbl2. Racchek to ale napsal jako chápavý student – sám to nepovažoval za důležité, ale uvědomil si, že se v oblasti neorientuje natolik dobře, aby to dokázal sám posoudit. Proto uvedl i tuhle informaci, o které si myslel, že je nadbytečná (proto ji neformuloval úplně přesně). Uvedl ji jen pro jistotu, kdyby to náhodou mělo vliv, aby s tím mohli znalejší lidé pracovat a upozornit ho, že na tom záleží.

Pokud tento stav zakryjete INNER JOINEM, můžete zaplakat nad výdělkem. Bohatě stačí, aby chtěl Racchek vybrat záznamy které mají allowed=0 NEBO nemají odpovídající záznam, a už je v háji a bude přepisovat nejen podmínku, ale i JOINY.
Ano, když se změní pravidla spojování, musí se přepsat JOINy. Když bude chtít tbl1 spojit s tabulkou tbl3, bude také muset přepsat JOIN. Výhoda je, že jsou pravidla pro spojování uvedena jinde, než podmínky, takže se to navzájem neplete.

SQL je velmi chytře navržené, ne nadarmo jsou HAVING, WHERE a ORDER BY až na konci - v nich se máte rejpat. Co je nad nimi má být co nejvíc zobecněné.
Ano, SQL je chytře navržené, proto odděluje spojovací podmínky od filtrovacích. Akorát vy se bůhvíproč snažíte spojovací podmínku nacpat do filtrovacích, i když to tazatel v původním dotazu velmi viditelně oddělil. Resp. Racchek dotaz formuloval tak, že ani nic jiného, než INNER JOIN nepředpokládal – dokonce ani první diskutující nenapadlo, že by to mohlo být i jinak. Teprve pak se někdo začal zabývat tím dovětkem, že v tbl2 záznamy nemusí existovat, a začal řešit, zda to je nebo není důležité. Racchek tenhle dovětek mezi podmínkami vůbec neuváděl, evidentně to tedy nevnímal jako podmínku, ale jako přirozený důsledek spojení.

Dotaz je zobecněný, pokud JOINovací podmínky máte u JOINu a ne ve WHERE. Když nacpete JOINovací podmínku do WHERE, musíte na to myslet při každé změně WHERE, pořád si musíte hlídat, abyste tu podmínku do WHERE připojil správně. Dotaz je zobecněný tehdy, pokud ve WHERE necháte opravdu jen filtrovací podmínky. Když jsem potřeboval spojit tbl1 se záznamy z tbl2, které mají kategorie=1 (právě takhle bylo formulované zadání – že se spojuje s podmnožinou druhé tabulky), dal jsem i tu podmínku na kategorie=1 do JOINu. Aby všechny spojovací podmínky byly u JOINu a já nemusel hlídat, že je správně přilepuju ke každému možnému WHERE. Dokonce možná z toho JOINu následně vznikl pohled, tím už si nejsem jistý.

e3k

  • ***
  • 217
    • Zobrazit profil
    • E-mail
Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #86 kdy: 12. 10. 2019, 21:11:38 »
odpověděl
Ospravedlnujem sa ale Filip a Miroslav tu narobili taky bordel ze sa to da tazko citat.
Kazdopadne pri druhom zadani prikladu by uz INNER JOIN uplne stacil.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #87 kdy: 13. 10. 2019, 10:31:00 »
.
Kazdopadne pri druhom zadani prikladu by uz INNER JOIN uplne stacil.

On už by při prvním zadání stačil INNER JOIN, o tom není vůbec pochyb. Jen je to špatně navržené.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #88 kdy: 13. 10. 2019, 10:58:53 »
Jen je to špatně navržené.
Na tomhle dotazu se evidentně neshodneme. Jak by tedy podle vás vypadal správně navržený SELECT pro tohle zadání?

Chci všechny záznamy z tbl2, které mají allowed > 0, a k nim připojit odpovídající záznam z tbl1. Pro každý záznam z tbl2 existuje záznam v tbl1.

Re:MySQL - podmíněný SELECT přes dvě tabulky
« Odpověď #89 kdy: 13. 10. 2019, 11:04:29 »
Na tomhle dotazu se evidentně neshodneme. Jak by tedy podle vás vypadal správně navržený SELECT pro tohle zadání?

Ale my se v zásadě shodujeme, obě řešení dávají tentýž výsledek.
Pře je pouze o tom, jestli je dobré přemýšlet trochu dopředu a tvořit s k takovému přemýšlení návyk.

Chci všechny záznamy z tbl2, které mají allowed > 0, a k nim připojit odpovídající záznam z tbl1. Pro každý záznam z tbl2 existuje záznam v tbl1.

Chápu kam míříte, ale zkoušíte to trochu demagogicky. Hlavní entitou dotazu je tbl1, z ní se čerpají informace. V tbl2 je pouze přívěsek, který existovat může a nemusí. Takže nemůžete z tbl2 najednou udělat hlavní entitu.