Autor Zpráva
Michael241
Profil *
Dobrý den,


měl bych jednu prosbu o radu.

Mám 3 tabulky, a v tabulce `produkt` potřebuji měnit aktuální stav při změně skladu.
To již mám hotové, problém nastavá v situaci, kdy je produkt v SETU - to by problém nebyl, problém je, pokud je zařazen u více produktů (tedy může být v setu s 5 druhy produkty,
např jedná se o produkt "Obal na knihu" a ten je v setu s 10 různýma knihama, a 3 dalšíma věcma za jinou cenu.)

Stav skladu setu funguje tak, že je skladem nejmenší množství minimálně jednoho produktu.
Tedy je skladem 5 knih, 12 obalů, 20 pravítek, tak sklad setu bude 5.
- Pokud se prodá zvlášť 1 obal, sklad bude stále 5
- Pokud se ale prodá zvlášť 1 kniha, sklad musí být 4


Stručně mám tabulky:
produkt (id, aktualni_stav)
produkt_sklad (id, produkt_id, sklad_id, mnozstvi)
produkt_set (id, proukt_id, produkt_set_id)

Abych to doplnil - funguje vše fajn, jen nefunguje to, že id_set_karty může být pole (když doplním LIMIT 1 tak funguje, což nemohu protože potřebuji aktualizovat všechny karty)
(může být kombinovaný u více produktů, jak jsem psal) a já potřebuji měnit stav dle produktů v daných setech.


a SQL

DROP TRIGGER aktualizace_skladu;
DELIMITER $$

CREATE TRIGGER aktualizace_skladu
AFTER UPDATE ON produkt_sklad FOR EACH ROW 
 
BEGIN
 
    DECLARE id_set_karty INT DEFAULT 0;

    SELECT produkt_id INTO id_set_karty FROM produkt_sklad WHERE produkt_set_id = NEW.produkt_id;
 
     UPDATE produkt p  SET p.aktualni_stav = COALESCE( 
        ( SELECT SUM(mnozstvi) FROM produkt_sklad 
             WHERE produkt_id = NEW.produkt_id 
     ), 0 ) WHERE p.id = NEW.produkt_id;
 
    END IF;

    /* aktualizace SET */
    IF is_in_set>0 THEN
 
        UPDATE produkt p SET p.aktualni_stav = COALESCE(
                ( SELECT MIN(aktualni_stav) FROM produkt WHERE id IN( 
                    SELECT produkt_set_id FROM produkt_set WHERE produkt_id = id_set_karty 
                )
        ), 0) WHERE p.id = id_set_karty;

    END IF;
 
END;
ttttttttttt
Profil *
Je to kompletní? is_in_set není definované.

Celý ten trigger mi přijde zbytečně složitý. Když se produktu sníží množství, tak stačí všem produktům ze setu nastavit aktuální stav na least(aktualni_stav, NEW.mnozstvi), ne? Dá se to celé nahrazit za něco jako


UPDATE produkt p  SET p.aktualni_stav = least(aktualni_stav, NEW.mnozstvi) WHERE p.id IN (SELECT proukt_id FROM produkt_set WHERE produkt_set_id = NEW.produkt_id)
?

Pokud ne, proč?
Michael241
Profil *
pardon, is_in_set je (má být) id_set_karty, špatně jsem to napsal.

No nevypadá to vlastně špatně, jen co vidím za problém je, že toto by sice fungovalo a aktualizovalo produkt na případně menší sklad než má, ale nemohu tam použít least(aktualni_stav, NEW.mnozstvi) protože NEW.mnozstvi neni celkový stav, je to pouze množství na jednom skladu, které se zrovna upravilo. ještě je možnost sklad 2, 3...proto tam mám COALESCE ( SELECT SUM(amount)... protože může být na více skladech..

Takže mě vlastně napadá v least - NEW.mnozstvi nahradit za ( SELECT aktualni_stav FROM produkt WHERE id = NEW.produkt.id ) což by mělo vrátit celkový, aktuálně upravený sklad ?
Michael241
Profil *
PS 2 - To tvoje vlastně nereflektuje to, když množství naskladním.

Tj. aktualni_stav setu 6 ks => sklad produktů je v setu je nyní ale naskladněn na
- 8 ks (první díl setu) a
- 11 ks druhý díl setu

ale neprovádí to aktualizaci, nechává to stále 6 ks, protože to bere (6, 11)
ale SET má mít teď sklad 8ks (nejmenší sklad jednoho dílu)


Tak vyřešil jsem to zatím takto, ale ještě úplně nevím jestli to bude OK.


UPDATE produkt p  SET p. aktualni_stav = ( 
  SELECT MIN(aktualni_stav) FROM produkt WHERE id IN(  
    SELECT produkt_set_id FROM produkt_set WHERE produkt_id = p.id 
    )
)
WHERE p.id IN  (
    SELECT produkt_id FROM produkt_set 
    WHERE produkt_set_id = NEW.product_id
);
ttttttttttt
Profil *
Dobrá připomínka, nedošlo mi, že tam je víc skladů. Při zvyšování počtu položek to nefunguje, to je taky pravda.

Nemám moc rád, když je v triggerech netriviální logika, tou je pro mě SELECT, který čte jiné řádky, tak bych se tomu řešení osobně spíš vyhnul. Budeš potřebovat ještě AFTER INSERT, AFTER DELETE triggery. Pokud máš kaskádové mazání přes cizí klíče, tak je dobré si rozmyslet, co se stane při smazání produktu. Nejspíš se jen ta aktualizace zavolá vícekrát na smazaném záznamu, takže kromě pár dotazů navíc nic.

Pokud těch produktů není moc (tisíce jsou imho pořád ok), taky bych to řešil přes VIEW a aktuální množství dopočítával. Myslím, že to se správými indexy pořád bude dostatečně rychlé (milisekundy) a robustnější. Případně pak materializovaný pohled, pokud ho databáze podporuje.

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