Autor Zpráva
SteveO
Profil *
Dobrý den,

Mám SQL dotaz:
SELECT .... WHERE p.status = 1 AND (SELECT category_id FROM product_to_category ap2c WHERE ap2c.product_id = p.product_id ORDER BY ap2c.product_id DESC LIMIT 1) NOT IN (92)

Ten sice funguje, ale ne úplně správně v případě, že k produktu patří více kategorií. Lze to nějak upravit tak, abych mohl ze subquery ostranit limit, vracela by všechny odpovídající kategorie, mezi kterými bych pak hledal ID, která nechci? A také, aby podmínka vyhovovala, i když produkty nepatří do žádné kategorie.

Díky.
juriad
Profil
Máš tabulku product a tabulku product_to_category s vazbou 1:N. Chceš produkty, které nejsou v kategorii 92 a mají status 1?
Nechápu vůbec proč tam máš ten ORDR BY a LIMIT.
SteveO
Profil *
Protože v tabulce product_to_category může být:

product_id, category_id
1, 92

ale také:

product_id, category_id
2, 92
2, 123
2, 59

nebo:

product_id, category_id
3, 50
3, 123
3, 92

Začínám se obávat, že už jsem z toho tak vyfluslej, že řeším kraviny :D
juriad
Profil
SteveO:
Ok, dal jsi nám data, teď nás zajímá, co má být výsledkem dotazu. Proč by mělo záležet na pořadí záznamů v tabulce product_to_category? (Nesmí, databáze pořadí vůbec negarantuje).

Ještě jednou tedy:
Chceš produkty, které nejsou v kategorii 92 a mají status 1?
SteveO
Profil *
Chceš produkty, které nejsou v kategorii 92 a mají status 1? -> ANO, ale možná bude později potřeba vynechat produkty třeba z 10 kategorií (kategorií jsou stovky).
juriad
Profil
Skvěle.

SELECT p.*
FROM products p
LEFT JOIN product_to_category ap2c ON ap2c.product_id = p.product_id AND ap2c.category_id IN (92)
WHERE p.status = 1 AND ap2c.product_id IS NULL

Toto ke každému produktu přidá kategorii ze seznamu zakázaných. A pak vyfiltrujeme jen ty, u kterých se mu to nepodařilo.

Ono to z:
product_name, produkt_id, status
kalhoty, 1, 1
košile, 2, 1
pantofle, 4, 1
čepice, 5, 1

product_id, category_id
4, 30
4, 29

Napřed vytvoří (připojí záznam o kategorii nebo NULL) *:
kalhoty, 1, 1, 1, 92
košile, 2, 1, 2, 92
pantofle, 4, 1, NULL, NULL
čepice, 5, 1, NULL, NULL

* kdyby ťěch zakázaných bylo víc u jednoho produktu, tady by se oběvily třeba ty kalhoty vícekrát, ale to nevadí, protože v dalším kroku se ty záznamy odstraní.

A pak to WHERE podmínka profiltruje na výsledné:
pantofle, 4, 1
čepice, 5, 1

Funguje to pro produkty bez kategorií, i produkty s více kategoriemi, produkt může mít dokonce libovolný počet zakázaných kategorí.
SteveO
Profil *
Nemám slov... jednoduché a geniální! Díky moc.

Já to zkoušel i takto:
LEFT JOIN product_to_category p2c ON p2c.product_id = p.product_id
..
WHERE p2c.category_id NOT IN (92)

Ale vracelo mi to i produkty z té vyjmuté kategorie, můžeš mi ještě prosím vysvětlit, proč?
juriad
Profil
SteveO:
Můžu. Tím jsi řekl, že chceš k produktům přidat informaci o kategorii; filtrování WHERE se provádí později. Takže po JOINu vypadají data:
kalhoty, 1, 1, 1, 92
košile, 2, 1, 2, 92
košile, 2, 1, 2, 123
košile, 2, 1, 2, 59
pantofle, 4, 1, 4, 30
pantofle, 4, 1, 4, 29
čepice, 5, 1, NULL, NULL

A pak se provede ta WHERE podmínka. Výsledek je asi zřejmý:
košile, 2, 1, 2, 123
košile, 2, 1, 2, 59
pantofle, 4, 1, 4, 30
pantofle, 4, 1, 4, 29
A má to i tu chybu, že odstraní ten NULL, protože neznámá hodnota může být v seznamu (92).

Tím, že přidáš do té vazební podmínky požadavek na zakázané kategorie děláš to samé jako:
SELECT p.*
FROM products p
LEFT JOIN (SELECT * FROM product_to_category ap2c WHERE ap2c.category_id IN (92)) x ON x.product_id = p.product_id
WHERE p.status = 1 AND x.product_id IS NULL

V příkladu jsem měl chybu s NULLem (má být v obou posledních sloupcích, nikoli jen v jednom).
SteveO
Profil *
Hmm, ale zde v tvém výsledku WHERE podmínky je to správně, 92 tam není... a já ji tam měl :)

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