reklama
Aktuality  |  Články  |  Recenze
Doporučení  |  Diskuze
Grafické karty a hry  |  Procesory
Storage a RAM
Monitory  |  Ostatní
Akumulátory, EV
Robotika, AI
Průzkum vesmíru
Digimanie  |  TV Freak  |  Svět mobilně

[MySQL] Zase trigger.. :(

kikloop (140)|5.6.2008 11:02
takze, sice pri pisani tohto topicu som dany problem uz vyriesil, ale uplne inou cestou. kazdopadne by ma zaujimalo, ci je mozne tento problem riesit aj povodne myslenym sposobom.

Tu je moj trigger
[code]
delimier |
CREATE TRIGGER `it_zberdat`.`RevEntry` BEFORE UPDATE ON `it_zberdat`.`prehlad`
FOR EACH ROW BEGIN
IF (new.aktivna="n") THEN
INSERT INTO poznamka values(0,old.iid,old.uid,old.polozka,"Polozka bola odobrana",now(),"revoke");
ELSE
INSERT INTO poznamka values(0,old.iid,old.uid,old.polozka,"Polozka bola reaktivovana",NOW(),"assign");
END IF;
END
|
delimiter ;
[/code]
Takze, trigger robi to, ze po zmene udajov v tabulke prehlad zapise do tabulky poznamky vykonanu zmenu.. konkretne zmenu hodnoty stlpca aktivna.

Problem bol v sposobe vkladania zaznamov, ktory pri viacnasobnom odobrani a prideleni polozky viacerym osobam vytvaral duplicitne riadky v tabulke prehlad a teda pri zmene udajov bol vysledny pocet ovplyvnenych riadkov napriklad 3 a teda 3x spusteny trigger a 3 nove riadky v tabulke poznamky. A to som prave potreboval eliminovat na jedna zmena = jeden riadok..

Tu je syntax tvorby triggera z Mysql doc.
[quote]
CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW trigger_stmt
[/quote]

Hlavna otazka teda znie : Da sa nejakym sposobom nahradit FOR EACH ROW inou syntaxou, tak aby pri viacnasobnom spusteni bol trigger vykonany prave 1x a nie 3x ? Nikde som ziadne ine moznosti nenasiel.. uplne laicky..ak by sa to dalo nahradit FOR LAST ROW :D

No a problem som nakoniec vyriesil tak, ze som odstranil duplicitne riadky a zmenil syntax INSERTu na syntax INSERT INTO .. ON DUPLICATE KEY UPDATE... http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Ritchie83 (369)|7.6.2008 14:05
[QUOTE=kikloop;129509]Da sa nejakym sposobom nahradit FOR EACH ROW inou syntaxou, tak aby pri viacnasobnom spusteni bol trigger vykonany prave 1x a nie 3x ? Nikde som ziadne ine moznosti nenasiel.. uplne laicky..ak by sa to dalo nahradit FOR LAST ROW :D[/QUOTE]
Pokud je v manuálu syntaxe s FOR EACH ROW napsána jako nevariantní, tak zjevně není variantní. Klíčové slovo LAST ROW nedává příliš nesmysl, protože nemůžete zaručit, v jakém pořadí budou řádky aktualizovány – vhodnější by tedy bylo něco jako ANY ROW. Jestliže správně chápu význam sloupce uid, tak se to tabulky poznamka zapisují různé řádky lišící se alespoň v uid. Jaké uid by se tedy podle vás mělo to tabulky zapsat při současném ovlivnění více řádků?

BTW Zapisovat do tabulky poznámka textový řetězec je dosti neefektivní, když tu samou informaci lze vyčíst i z posledního sloupce, který je pravděpodobně typu ENUM.

[QUOTE=kikloop;129509]No a problem som nakoniec vyriesil tak, ze som odstranil duplicitne riadky a zmenil syntax INSERTu na syntax INSERT INTO .. ON DUPLICATE KEY UPDATE... [/QUOTE]
Jelikož neznám detailní strukturu databáze, tak nemohu hodnotit, jak dobře jste problém vyřešil, ale něco mně říká, že to nebylo ve stylu best-practice.
kikloop (140)|9.6.2008 13:29
[code]
Tabulka POZNAMKA
`id` int(11) NOT NULL auto_increment,
`iid` mediumint(9) default NULL
`uid` smallint(6) default NULL
`polozka` enum('4gcard','simcard','notebook','telefon','licence','desktop') NULL,
`poznamka` text NOT NULL,
`pridane` datetime NOT NULL,
`typ` enum('add','assign','revoke','notice','warn','eol') default NULL,
PRIMARY KEY (`id`),
KEY `ix_iiditem` (`iid`,`polozka`),
KEY `ix_uid` (`uid`)
KEY 'ix_typ' ('typ')

tabulka prehlad
`id` int(10) unsigned NOT NULL auto_increment,
`uid` smallint(6) unsigned NOT NULL,
`iid` mediumint(9) unsigned NOT NULL,
`polozka` enum('4gcard','simcard','notebook','telefon','licence','desktop') NOT NULL,
`pridane` datetime default NULL,
`pridal` tinyint(4) unsigned NOT NULL,
`aktivna` enum('a','n') NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_iiditem` (`iid`,`uid`,`polozka`),
KEY `ix_uid` (`uid`),
KEY `ix_iid` (`iid`)
[/code]
- Problem s duplicitnymi hodnotami bol v tabulke prehlady, kedy pri znovu prideleni prostriedku sa zaznam neaktualizoval ale zapisal novy a teda existovalo viac zaznamov ktore vyhovovali podmienke triggeru new.aktivna=n. Problem som odstranil pridani unikatneho indexu na stlpce IID, UID, POLOZKa teda jeden uzivatel moze vlastnit len raz IID z danej polozky, ale moze vlastnit viac IID z danej polozky a viac rovnakych poloziek s inym IID. snad je to jasne :D Takze dalsi insert s rovnakymi hodnotami skonci chybou a preto ta syntax INSERT ON DUPLICATE KEY UPDATE..



- Poznamky je mozne pridavat uzivatelom, teda UID je vyplnene, POLOZKA a IID je v tom pripade NULL.
- Poznamky je mozne pridavat prostriedkom, teda IID a polozka su vyplenene, UID neni vyplnene..
- Poznamky je mozne pridavat kombinacii uzivatela a prostriedku - vsetky udaje su vyplnene.

[quote]
Jestliže správně chápu význam sloupce uid, tak se to tabulky poznamka zapisují různé řádky lišící se alespoň v uid. Jaké uid by se tedy podle vás mělo to tabulky zapsat při současném ovlivnění více řádků?
[/quote]
nejde o to, ale UID by sa malo zapisat, ale kolko riadkov sa pri spusteni triggeru zapise do tabulky poznamka. Doteraz to fungovalo tak, ze stary zaznam sa nastavil na aktivna =N a pre noveho vlastnika sa vytvoril novy zaznam aktivna=A, ak som pridelil danu polozku znovu prvemu uzivatelovi tak sa nezmenila stara ale vytvorila nova aktivna=A - pri odobrani aktivna=N - a tu bol problem, pretoze uz existovali 2 zaznamy, ktore vyhovovali podmienke kde UID je dany uzivatel, IID a polozka - dana polozka a aktivna=N - teda 2x trigger a 2 zaznamy v poznamke

[quote]
BTW Zapisovat do tabulky poznámka textový řetězec je dosti neefektivní, když tu samou informaci lze vyčíst i z posledního sloupce, který je pravděpodobně typu ENUM.
[/quote]
Uznavam, je to neefektivne, stlpec "typ" je indexovany i ked k efektivnosti prispieva len malo.. Stlpec poznamka je text - pretoze do tohto pola su okrem automatickych sprav zaznamenane aj poznamky konkretnych spravcov.
Logout (4018)|9.6.2008 13:40
Nechtěl bys ještě jaksi doplnit, k čemu ty tabulky sloužej? Jaký data se tam ukládaj?

Maj ty data mezi sebou nějakej vztah? Jestli jo, tak kde je referenční integrita?

Ty tabulky maj vetšinu sloupců stejnejch. To mě vede k myšlence, že ta struktura nebude asi optimální...
kikloop (140)|9.6.2008 14:45
OK :D tak to este nejak opisem + nejake tie vzorove data..
Sluzi to k evidencii prostriedkov vo firme pouzivanych zamestnancami. Teda pridelene sluzobne telefony, simkarty, notebooky. Je dolezite poznat historiu daneho prostriedku a uzivatela. Teda kto v minulosti vlastnil dany prostriedok a co v minulosti vlastnil dany uzivatel. - na to sluzi prave tabulka poznamky, kde sa vacsinou teda za pouzitia triggerov zapisuju automaticke spravy (Zaciatok evidencie polozky, polozka pridelena, odobrana, znovu pridelena, + poznamky administratorov - odoslane na reklamaciu, vratene, ukradnute, koniec zivnostnosti/ vyradenie z evidencie)

Existuju tabulky '4gcard','simcard','notebook','telefon','licence','desktop' - kde su ulozene udaje o jednotlivych prostriedkoch, datum nakupu, cislo faktury, zaruka do.. . Je snad jasne, ze struktura neni totozna takze neni mozne pouzit jednu tabulku.

vysvetlim teda tu tabulku PREHLAD:
ID - primarny kluc - auto increment - vsetko jasne :)
UID - ID uzivatela - tabulka_uzivatelov.id = prehlad.uid
IID - ID polozky - vybrana_polozka.id = prehlad.iid
polozka - rozhoduje z ktorej tabulky sa bude vyberat IID, teda ak tu bude simcard, tak simcard.ID = prehlad.IID AND prehlad.polozka='simcard'
.
.
pridal - ID administratora
aktivna - Priznak, ci je dany zaznam aktivny.

Vzorove data...
tabulka SIMCARD
[code]
ID SIMID TELCISLO PIN PIN2 PUK PUK2 BPIN TARIF
0 12346 775888888 124 ...
1 23456 775999999 589 ...
[/code]

tabulka PREHLAD
[code]
ID UID IID POLOZKA PRIDANE PRIDAL AKTIVNA
1 2 1 simcard 2008-08-08 1 A
2 2 5 simcard 2008-08-09 1 A
3 2 10 desktop 2008-08-09 1 A
4 2 11 telefon 2008-08-10 1 A
5 3 1 simcard 2008-08-01 1 N
[/code]
- Uzivatel 2 ma teda AKTIVNE pridelenu 1 SIM kartu s 5, a ma prideleny este jeden desktop s ID 10 a telefon s ID 11 + uzivatel UID=2 prevzal DRUHU SIM kartu od uzivatela UID=3 si IID=1.

V ktorej tabulke mam hladat zistim podla POLOZKA a co mam hladat je IID.

takze tabulka poznamky: - Tu pri triedeni podla casu/ datumu je mozne zistit historiu pohybov
[code]
ID IID UID POLOZKA PRIDANE TYP POZNAMKA
0 1 NULL simcard 2008-08-01 add Zaciatok evidencie
1 3 1 simcard 2008-08-02 assign Polozka pridelena
2 3 1 simcard 2008-08-03 revoke Polozka odobrana
3 2 2 simcard 2008-08-04 assign Polozka pridelena
[/code]
- Tu je priklad historie jednej polozky -
1. Trigger po vytvoreni zaznamu v tabulke SIMCARD automaticky prida zaznam do tabulky poznamka s informaciou o zaciatku evidencie. Este by som chcel vysvetlit UID = NULL - hovori o tom, ze sa zaznam tyka iba SIM karty. taktiez existuju zaznamy s null hodnotami pre IID a polozka ale UID je platna hodnota- to znamena ze sa jedna o poznamku k uzivatelovi.
2. Trigger po vytvoreni zaznamu v tabulke PREHLAD automaticky prida poznamku o prideleni prostriedku uzivatelovi
3. Trigger pri UPDATE tabulky PREHLAD na AKTIVNA=N automaticky prida poznamku o odobrani prostriedku
4. a znova pridelena polozka inemu uzivatelovi..

Chcel by som este pripomenut ze sa snazim riesit to, ako pri vyskyte viacerych znaznamov v podmienke TRIGGERU, spustit telo iba 1x :)
Logout (4018)|9.6.2008 15:27
Problém je v tom, že ty tabulky dublujou údaje. Takový tabulky se vždycky bbě aktualizujou a hrozí rozsynchrnonizování. Doporučil bych Ti todle:
1) Zruš tabulku PREHLED. Nenese žádnou informaci. To, že měl "uživatel 3" kdysi přidělenou simku a teď ji má "uživatel 2" jde odvodit z tabulky POZNAMKA. Pokud potřebuješ, tak si pro tabulku PREHLED napiš VIEW nebo STORED PROC. Odpadnou ti veškerý problémy s trigerama.
(aktivní jsou ty přidělení, pro který neexistuje následující odebrání - jednoduchej JOIN přes sebe sama).

Další nápady, jak to zlepšit:
2) Přejměnuj tabulku POZNAMKA - to jméno je hodně nedeskriptivni. Co třeba ZMENYSTAVU?
3) TYP udělej jako INTEGER FOREIGN KEY do nové tabulky CISELNIK, nebo třeba POZNAMKA, kde budou uvedený textový významy toho typu.
4) Udělej tabulku EVIDENCE, kde budou všechny evidované prostředky nezávisle na typu. ID těchto prostředků bude odkazovat do tabulky ZMENYSTAVU a zaroven do jednotlivejch tabulek obsahujicich specialni atributy pro danej typ veci. Tim získáš relativně funkční referenční integritu (např. pro smazání položky pak při dobře definovanejch FK stačí vymazat položku z tabulky EVIDENCE.


Možná se Ti to zdá hnidopišství, ale jestli to neni vyloženě jednorázová věc a počítáš s tim, že se to bude rozrůstat, upravovat, tak se Ti tydle úpravy mnohokrát vyplatěj.
Logout (4018)|9.6.2008 16:16
Ještě další myšlenky:
místo událostí přiděleno, odebráno bych do tabulky EVIDENCE dal sloupeček OD a DO (zarazeni a vyrazeni z evidence) a do tabulky ZMENASTAVU dej misto PRIDANE taky sloupecky OD a DO (odkdy a dokdy byl pridelen prostredek danemu cloveku). Pak vlastne i sloupecek typ bude zbytecny. DO IS NULL bude znacit dodnes.

jednoduse zjistis vsechny pridelene prostredky v dany cas:
SELECT * FROM ZMENASTAVU WHERE OD < DATUM AND (DO > DATUM OR DO IS NULL)
vsechny pridelene prostredky:
SELECT * FROM ZMENASTAVU WHERE DO IS NULL
vsechny nepridelene prostredky:
SELECT * from EVIDENCE WHERE ID NOT IN (SELECT * FROM ZMENASTAVU WHERE DO IS NULL)
atd...
kikloop (140)|10.6.2008 08:37
Diky za kazdopadne dobre pripomienky :)

1. Zrusenie tab. PREHLAD - to by som momentalne mohol nejakym sposobom aplikovat. Uznavam, ze tieto informacie su vlastne duplicitne, ale to by som musel pravdepodobne aplikovat sucasne s pridanim stlpcov OD - DO.

2. tabulka POZNAMKA nesie naozaj len informacie o poznamkach, historii pohybov.. Nemyslim si ze ten nazov neni vystizny v danom kontexte :)

3. Ak si to myslel tak, ze by som zrusil stlpec POZNAMKA v tab. POZNAMKA a zo stlpca TYP spravil INT a FK na inu tabulku s indexom poznamok, tak o tom som vazne uvazoval. Je mi jasne ze 100x zapisovat text "pridana polozka" neni efektivne.. Je to vec zmeny SQL dotazu a nenarocnej upravy struktury. problem je v tom, ze sa tam zapisuju aj poznamky, ktore sa neopakuju :-/

4. ano, to by taktiez slo, ale myslim si, ze by to bolo az prilis sofistikovane riesenie, ktore by mi uz neprinieslo nejake relativne zvysenie vykonnosti kodu.

k stlpcom OD DO - ich vyuzitie vidim jedine pri zruseni tabulky prehlad. Pretoze momentalne tabulka prehlad nesie jednoznacnu informaciu o prideleni prostriedku. Je to vlastne tabulka aktualnych stavov. Tabulka poznamky je vlastne len historia.
Logout (4018)|10.6.2008 10:05
4) neni zkvuli vykonu, ale kvuli vytvoreni referencni integrity - spousta prace s databazi se pak zjednodussi, protoze neni treba propagovat zmeny do dalsich tabulek.
2) Pokud Ti nazev vyhovuje, OK :-D
1) Nemusel, akorat struktura od-do zjednodušuje dotazy. I tak je tabulka prehled duplicitna: např.

SELECT * FROM poznamky p1 LEFT JOIN poznamky p2 ON (p1.iid = p2.iid AND p1.pridane < p2.pridane)
WHERE p2.id IS NULL
(tzn. zaznamy z poznamek,kde neexistuje "novejsi" zaznam se stejnym iid)
Ti vrati aktualni stav vsech prostredku. Podminkou na typ pak ziskas prirazene, neprirazene, nikdy neprirazene (pouze zarazene do evidence).
kikloop (140)|16.6.2008 08:07
Tak nakoniec som par z tvojich rad uspesne aplikoval. Ci to bol spravny krok uvidim az casom, ked sa naplni databaza :D
Kadopadne davam + za diskusiu na urovni :)
Logout (4018)|16.6.2008 09:55
Tak ať Ti slouží :-)