Diskuze: Trigger s dvoma podmienkami.
V předchozím kvízu, Online test znalostí SQL a databází, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 25 zpráv z 25.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí SQL a databází, jsme si ověřili nabyté zkušenosti z kurzu.
oops, v popise situacie mam chybu, spravne ma byt
recovery_keys
Zdrojaky su napisane spravne.
Můžu se zeptat, k čemu u tohoto dotazu slouží ten "INNER JOIN"?
Podle mě se JOIN používá pro výpis, ale pro mazání je tam
zbytečný...
Nie je zbytocny. Bez neho by som musel mat dva prikazy "DELETE". Pre kazdu
tabulku zvlast.
Takto jednym prikazom DELETE vymazem z obidvoch tabuliek zaznamy s rovnakou
podmienkou - v mojom pripade je to email ako jedinecna hodnota v kazdej tabulke.
Takze ak najde vo vsetkych tabulkach zaznam s rovnakym emailom, tak ich vymaze
prislusne riadky.
Tak zkus místo INNER JOIN použít OUTER JOIN...
S JOIN-mi problem nie je.
Problem je, ze ak v tabulke recovery_keys nie je zaznam, tak
DELETE z tabuliek members a confirm_email sa
podla mojho prveho Triggeru nevykona.
A o to právě jde. INNER JOIN funguje, pokud jsou záznamy ve všech dotčených tabulkách, OUTER JOIN vybere i ty záznamy i které nejsou ve všech tabulkách...
Nastav si kaskádu. To znamená, že kdykoliv se smaže záznam v "rodičovské" (primární) tabulce, smažou se automaticky i odpovídající záznamy v podřízené tabulce. Používá se to, když tabulky popisují věci, které jedna bez druhé (podřízená bez nadřízené) nemají smysl. V tvém případě bude rodič members a dítě recovery_keys.
Jak na to: buď to jde naklikat nebo spusť následující skript:
ALTER TABLE recovery_keys ADD FOREIGN KEY (email) REFERENCES members (email) ON DELETE CASCADE
Správně by se nemělo svazovat podle emailu, ale podle rodičova Id, ale to teď nechme stranou.
Pak ti bude stačit jen ten druhý trigger. Ten smaže membera, a spolu s ním se díky kaskádě smažou i jeho záznamy z recovery_keys, pokud existují. Pokud ne, smaže se prostě jenom member (spolu s tím confirm_emailem, samozřejmě). Důležité je říct, že kaskáda funguje vždycky, takže memberovy recovery_keys se ti smažou i když vymažeš membera kdykoliv jindy, nejenom tím triggerem.
Diky moc za odpoved, ale neviem si s tym poradit.
Co přesně ti nejde? Prostě spusť ten skript a smaž ten první trigger a mělo by to fungovat.
Ten řádek s tím ALTER TABLE nedávej do toho triggeru, spust ho jen jednorázově.
No prave tomu sa chcem vyhnut. Ja chcem, aby to bezalo automaticky na
serveri.
Tie moje dva triggery vykonavaju presne co chcem.
Myslienka bola, ci by nebolo mozne spojit to do jedneho. Jedna uloha = jeden
trigger.
Keby to bolo na php, je to lahko osetrene cez if a
else, takze som hladal ci nie je mozne aj kaskadu napisat nejak
podobne.
Teď ti moc nerozumím, to poběží automaticky. Tu kaskádu stačí nastavit jen teď jednou, od té doby bude fungovat pořád. Aniž bys musel cokoliv dalšího dělat, zavolá se automaticky pokaždé, když se spustí ten trigger.
Ked to skusam spustit samostatne, dostanem tuto chybu:
Chyba v dotaze (1005): Can't create table `xxxxxx`.`#sql-241c_3852` (errno: 150 "Foreign key constraint is incorrectly formed")
Psotě si udělej 2 FK - v tabulkách recovery_keys a members:
ALTER TABLE members ADD FOREIGN KEY (email) REFERENCES confirm_email (email) ON DELETE CASCADE
ALTER TABLE recovery_keys ADD FOREIGN KEY (email) REFERENCES members (email) ON DELETE CASCADE
Toto provedeš pouze jednou, ne při každém mazání.
Tím se zajistí, že
Tu druhou kaskádu ať určitě nedělá. Psal, že po úspěšné
verifikaci záznam v DB smaže (předpokládám, že myslí záznam v tabulce
confirm_email), tím by si smazal i člena.
Jak jsem psal, kaskáda by měla
být jen tam, kde záznamy v tabulce-dítěti bez záznamu v rodičovské
tabulce nemají smysl.
Peter Schoeller: Ještě asi bude potřeba nastavit sloupec email v members jako unikátní. Takže nejdřív zkus spustit tohle:
ALTER TABLE members ADD UNIQUE (email)
A pak až tohle:
ALTER TABLE recovery_keys ADD FOREIGN KEY (email) REFERENCES members (email) ON DELETE CASCADE
Kdyby ani to nefungovalo, tak holt gůgli, ta chyba může být cokoliv. Dobré odpovědi jsou třeba tady.
Jinak podle tohohle by v delete měl fungovat i LEFT JOIN, takže pokud máš problémy s kaskádou, můžeš zkusit přepsat ten trigger takhle:
DELETE members, confirm_email, recovery_keys
FROM confirm_email
INNER JOIN members ON confirm_email.email = members.email
LEFT JOIN recovery_keys ON recovery_keys.email = members.email
WHERE date_confirm < DATE_SUB(NOW(), INTERVAL 1 DAY)
Diky moc, idem testovat dalej
Tu prvu podmienku mam splnenu uz pri registracii, kde pred INSERT dotaz
skontrouje ci sa uz email v DB nachadza.
Ano, mas pravdu, confirm_email sa po uspesnej verifikacii
zmaze.
Len v pripade, ak novy clen, ktory si neverifikuje ucet (prepokladany utocnik)
bude po 24 hodinach vymazany. Nielen z confirm_email, ale aj z
tabulky members.
A ako som pisal, niekedy (nie vzdy) to skusaju aj cez reset hesla. Tym sa
dostane zaznam aj do tabulky recovery_keys. A kedze email
zadany pri registracii neexistuje (lebo nie je ani verifikovany - priklad: abcd@example.com - ma platnu
strukturu, ale realne neexistuje), tak mi potom zbytocne v tych tabulkach
(recovery a confirm) ostavaju zaznamy.
Doteraz mam tam tie dva triggre. Oba funguju spolahlivo len otazka bola, ci by
to slo jednym.
Tu prvu podmienku mam splnenu uz pri registracii, kde pred INSERT dotaz skontrouje ci sa uz email v DB nachadza.
Jj, to děláš dobře, ale to je něco jiného. Ta unikátnost musí být nastavená vyloženě jako vlastnost toho sloupce, bez toho nepůjde nastavit ten foreign key. (Aspoň tak praví google.)
Případně pokud nechceš řešit kaskádu, tak prostě zkus ten trigger s
tím left joinem. Pak bys druhý trigger neměl potřebovat. Vyzkoušej a dej
vědět.
Uz pri tom prvom pokuse (ALTER TABLE) som dostal tutu chybu:
Chyba v dotaze (1062): Duplicate entry '' for key 'email'
Co robim zle?
DB je MYSQL, INNODB
Pravděpodobně máš v members několik záznamů, které mají ve sloupci email jako hodnotu prázdný textový řetězec. Můžeš si to prověřit:
SELECT COUNT(1) FROM members WHERE email = ''
Když bude výsledek větší než 1, tak je opravdu chyba v tomhle. Pak tedy prověř, že sloupec email může obsahovat hodnotu NULL (pokud ne, tak ho tak nastav). A pak můžeš ty prázdné řetězce změnit na NULL:
UPDATE members SET email = NULL WHERE email = ''
Diky... Jedna chyba odstranena.... jeden email nemal hodnotu - ten moj
Teraz je dalsia chyba:
Chyba v dotaze (1452): Cannot add or update a child row: a foreign key constraint fails (`my-db_admin`.`#sql-241c_5770`, CONSTRAINT `#sql-241c_5770_ibfk_1` FOREIGN KEY (`email`) REFERENCES `members` (`email`) ON DELETE CASCADE)
A este raz diky za pomoc....
Není zač, ikdyž bys mohl zkoušet trochu googlit. Hned první odkaz by tě navedl na pravděpodobnou odpověď:
Nejspíš máš v recovery_keys záznamy, které nepatří žádnému memberovi.
Zbav se jich:
DELETE FROM recovery_keys
WHERE email NOT IN (SELECT email FROM members)
Jeeeeee.... Konecne to funguje
Mas u mna pivo "Kölsch"
Ten odkaz na googli som nasiel aj ja, ale ak vidim v odkaze "DROP" (tusim tretia
rada v tom odkaze) tak sa tomu oblukom vyhybam No po troch dnoch skusania uz
mi to nemysli
Hned som aj pochopil (snad) ako to funguje
Zobrazeno 25 zpráv z 25.