SQL: Ako na problematicky right join?

hknmtt

  • ****
  • 250
    • Zobrazit profil
    • E-mail
SQL: Ako na problematicky right join?
« kdy: 22. 02. 2025, 16:16:47 »
Riesim situaciu, kedy mam tabulu s id-ckami, kde su dva typy obsahu, a potrebujem jeden z tych typov filtrovat joinom, ale ponechat ten druhy mez zmeny.

Povedzme, ze mam jeden typ stranka a druhy typ clanok, ktory ma kategorie.

Inak povedane, mam tabulku content, kde mam 1:clanok, 2:stranka, 3:clanok, 4:stranka, 5:clanok a potrebujem spravit join na druhu tabulku categories a odfiltrovat clanky, ktore nie su v zozname dodanych kategorii, ale s tym, ze stranky sa zachovaju, kedze sa ich to netyka.

Jednoduche riesenie je spravit right join na categories tabulku, co mi odfiltruje clanky. Lenze right join tym padom zahodi stranky z content tabulky, kvoli absencii zhody na id-cku v tabulke categories. Ak spravim zase left join, tak viem spravit napriklad (category is null or in(..)), cim si odfiltrujem clanky, ktore nie su v zozname katagorii ktore chcem, a ze stranky budu mat NULL, kedze v tej joinutej categories tabulke vobec nie su.

Problem vsak je, ak clanok nema nastavenu ziadnu kategoriu, tak sa vyhodnoti ako is null a ostane v zozname.

Normalne by som mal dve samostatne tabulky a logiku oddelil, lenze tak by som nevedel strankovat obsah ako jeden celok. A nejak neviem ako to vyriesit teraz.

Napada ma asi pouzit nejaku sub-query alebo self join, ale nie som si uplne isty ktore riesenie je spravne.


hknmtt

  • ****
  • 250
    • Zobrazit profil
    • E-mail
Re:SQL: Ako na problematicky right join?
« Odpověď #1 kdy: 22. 02. 2025, 16:31:08 »
Asi je navhodnejsie pouzit nieco ako:

Kód: [Vybrat]
SELECT id FROM content WHERE type = stranka OR id IN(SELECT id FROM content RIGHT JOIN categories USING(id) WHERE categories.category = X) ORDER BY id ASC
Akurat neviem aky to bude mat dopad na vykon.

Re:SQL: Ako na problematicky right join?
« Odpověď #2 kdy: 22. 02. 2025, 20:10:03 »
Kód: [Vybrat]
SELECT co.id FROM content co
LEFT JOIN categories ca ON co.categoryId = ca.id
WHERE ca.id IS NOT NULL
  OR co.type = 'stranka'

Tohle by mělo zachovat všechny záznamy content, co mají typ 'stranka' bez ohledu na cokoliv dalšího + záznamy content, co mají jiný typ než 'stranka' a mají categoryId vyskytující se v category.
Nebo jsem špatně pochopil požadavek?
« Poslední změna: 22. 02. 2025, 20:11:52 od Tomas-T »

hknmtt

  • ****
  • 250
    • Zobrazit profil
    • E-mail
Re:SQL: Ako na problematicky right join?
« Odpověď #3 kdy: 22. 02. 2025, 20:55:22 »
Kód: [Vybrat]
SELECT co.id FROM content co
LEFT JOIN categories ca ON co.categoryId = ca.id
WHERE ca.id IS NOT NULL
  OR co.type = 'stranka'

Tohle by mělo zachovat všechny záznamy content, co mají typ 'stranka' bez ohledu na cokoliv dalšího + záznamy content, co mají jiný typ než 'stranka' a mají categoryId vyskytující se v category.
Nebo jsem špatně pochopil požadavek?

Diky, mal som uz funkcnu verziu, ale toto ma inspirovalo ju znacne zjednodusit.

Re:SQL: Ako na problematicky right join?
« Odpověď #4 kdy: 23. 02. 2025, 07:01:22 »
Kód: [Vybrat]
SELECT co.id FROM content co
LEFT JOIN categories ca ON co.categoryId = ca.id
WHERE ca.id IS NOT NULL
  OR co.type = 'stranka'

Tohle by mělo zachovat všechny záznamy content, co mají typ 'stranka' bez ohledu na cokoliv dalšího + záznamy content, co mají jiný typ než 'stranka' a mají categoryId vyskytující se v category.
Nebo jsem špatně pochopil požadavek?

Diky, mal som uz funkcnu verziu, ale toto ma inspirovalo ju znacne zjednodusit.

Podmínky s OR mohou mít problémy s výkonem - záleží jaká jsou data, jak máte indexy i jakou máte databázi (a jakou verzi). Samozřejmě, že záleží i na velikosti dat a intenzitě provozu. V některých (dnes spíš hraničních) případech je nutné dotaz přepsat na UNION.


LeosB

Re:SQL: Ako na problematicky right join?
« Odpověď #5 kdy: 23. 02. 2025, 12:13:02 »
Podmínky s OR mohou mít problémy s výkonem - záleží jaká jsou data, jak máte indexy i jakou máte databázi (a jakou verzi). Samozřejmě, že záleží i na velikosti dat a intenzitě provozu. V některých (dnes spíš hraničních) případech je nutné dotaz přepsat na UNION.

To se ještě dneska vážně používají databáze, které tyto sémanticky shodné zápisy (s OR nebo s UNION) nedokáží převádět automaticky (podle toho co je pro ně výhodnější na provedení) a nutí k tomu programátora?

Re:SQL: Ako na problematicky right join?
« Odpověď #6 kdy: 23. 02. 2025, 21:18:11 »
Podmínky s OR mohou mít problémy s výkonem - záleží jaká jsou data, jak máte indexy i jakou máte databázi (a jakou verzi). Samozřejmě, že záleží i na velikosti dat a intenzitě provozu. V některých (dnes spíš hraničních) případech je nutné dotaz přepsat na UNION.

To se ještě dneska vážně používají databáze, které tyto sémanticky shodné zápisy (s OR nebo s UNION) nedokáží převádět automaticky (podle toho co je pro ně výhodnější na provedení) a nutí k tomu programátora?

Jsou takové databáze a hodně se používají. PostgreSQL to nedělá 100%, MySQL a MariaDB pravděpodobně také ne. U Postgresu není problém v transformaci (transformace by se ani dělat nemusela, jde o podobu finálního plánu) - takový patch už byl vytvořený, a měl pár stovek řádek, ale v rozhodnutí, kterou cestu preferovat - jestli bitmap indexscan nebo merge index scanu nebo ještě něco jiného. U výrazů s OR jsou větší problémy s odhady, a kvalita odhadu je základ.

jjrsk

  • *****
  • 705
    • Zobrazit profil
Re:SQL: Ako na problematicky right join?
« Odpověď #7 kdy: 26. 02. 2025, 17:27:18 »
To se ještě dneska vážně používají databáze,...
Ony se pouzvaji databaze, ktery ti klidne pro jedno query vygenerujou 20 ruznych exekucnich planu. Z toho jeden bude ten (semi)idealni a 2-3 budou zcela katastrofalni. Ten zbytek bude nekde mezi.

A forma zapisu(mimo jine) kupodivu vede na to, ze ta databaze generuje lepsi plan.

I v tomhle jednoduchym pripade se ti muze stat (a zcela jiste obcas stane) ze to probehne tak, ze se nejdriv udela ten join pres vsechny zaznamy a teprve pak se to bude filtrovat. A kdyz tech zaznamu bude hodne .... bude klidne i radove vykonejsi ten union.