{"id":449,"date":"2010-12-27T14:04:36","date_gmt":"2010-12-27T13:04:36","guid":{"rendered":"https:\/\/d-mueller.de\/blog\/?p=449"},"modified":"2016-01-11T23:35:17","modified_gmt":"2016-01-11T22:35:17","slug":"mysql-inputvalidierung-mit-triggern","status":"publish","type":"post","link":"https:\/\/d-mueller.de\/blog\/mysql-inputvalidierung-mit-triggern\/","title":{"rendered":"MySQL Inputvalidierung mit Triggern"},"content":{"rendered":"<p>Ich finds sehr praktisch, direkt auf Datenbankseite soviel wie m\u00f6glich zu erledigen. Da wirds dann auch noch einen Artikel zu geben. Ich wurde neulich von Oracle inspiriert, wo folgende Konstrukte m\u00f6glich sind:<\/p>\n<pre data-enlighter-language=\"sql\" class=\"EnlighterJSRAW\">\r\ncreate table Product\r\n( \r\n\tProdNr integer constraint PK_Product primary key,\r\n\tProdPreis integer constraint min_price check (ProdPreis &gt;= 10)\r\n);\r\n<\/pre>\n<p>Damit rejected Oracle Werte kleiner als 10 f\u00fcr ProdPreis beim Insert \/ Update &#8211; super Sache und besser als das in der Application-Logik ausschlie\u00dfen zu m\u00fcssen. Einzig doof daran ist, dass man solche Fehler sinnvoll im Programm abfangen muss und mit sprechenden Fehlermeldungen quittieren muss &#8211; sonst kanns f\u00fcr unbedarfte Programmierer verwirrend werden, warum denn gewisse Werte nicht in der Datenbank eingef\u00fcgt werden k\u00f6nnen.<\/p>\n<h2>Check ist cool &#8211; aber nicht f\u00fcr MySQL<\/h2>\n<p>Zwar ist <i>check<\/i> auch in MySQL implementiert, tut aber einfach mal <b>nichts<\/b>. Als Workaround kann man f\u00fcr sowas <i>Trigger<\/i> verwenden, die vor Updates \/ Inserts automatisch aufgerufen werden und damit den gleichen Zweck erf\u00fcllen.<\/p>\n<p>Sowas kann dann zum Beispiel so aussehen:<\/p>\n<pre data-enlighter-language=\"sql\" class=\"EnlighterJSRAW\">\r\nDELIMITER \/\/\r\n\tCREATE TRIGGER min_price_four_ins \r\n\tBEFORE INSERT ON pizza \r\n\tFOR EACH ROW \r\n\tBEGIN \r\n\t\tDECLARE foobar INT;\r\n\t\tIF NEW.price &lt; 4 THEN \r\n\t\t\tSELECT `Das ist die Fehlermeldung` INTO foobar FROM pizza;\r\n\t\tEND IF; \r\n\tEND; \/\/\r\nDELIMITER ;\r\n<\/pre>\n<p>Erstmal kryptisch und verwirrend, schauen wir uns das mal step-by-step an:<\/p>\n<ol>\n<li>Der Trigger wird vor einem Insert auf die Tabelle <i>pizza<\/i> ausgef\u00fchrt.<\/li>\n<li><i>FOR EACH ROW<\/i>: Der Trigger wird f\u00fcr jede einzuf\u00fcgende Zeile ausgel\u00f6st<\/li>\n<li>Es wird eine int-Variable angelegt und eine Fehlermeldung als String in diese Variable eingelesen. Hier wirds verwirrend. Das Konstrukt ist deswegen n\u00f6tig, weil der Trigger fehlschlagen muss, um das Insert zu verhindern. Nun gibt es in MySQL kein <i>throw exception<\/i> oder <i>fail()<\/i>, also muss anderweitig ein Fehler ausgel\u00f6st werden. In diesem Fall wird also ein String in eine int-Variable eingelesen.<\/li>\n<\/ol>\n<p>Schauen wir uns die Funktion des Triggers mal an:<\/p>\n<pre data-enlighter-language=\"sql\" class=\"EnlighterJSRAW\">\r\nINSERT INTO pizza (pizzaname, price) VALUES (&#039;Salami&#039;, 3.95);\r\n<\/pre>\n<p>Und &#8211; wie erwartet &#8211; wird keine Zeile eingef\u00fcgt und die Fehlermeldung ausgegeben:<\/p>\n<pre data-enlighter-language=\"enlighter\" class=\"EnlighterJSRAW\">\r\n#1054 - Unknown column &#039;Das ist die Fehlermeldung&#039; in &#039;field list&#039;\r\n<\/pre>\n<p>Der Trigger muss nun nochmal f\u00fcr Update angelegt werden und schon ist die nicht vorhandene Check-Funktionalit\u00e4t emuliert.<\/p>\n<p>Mit Triggern l\u00e4sst sich nat\u00fcrlich noch viel mehr machen, etwa auch andere Tabellen abfragen, Werte updaten etc. <b>Aber Vorsicht:<\/b> Es sollte irgendwo an prominenter Stelle im Programmcode selbst notiert werden, welche Trigger existieren und was sie genau f\u00fcr eine Funktion haben. Sonst kann sowas zu gro\u00dfer Verwirrung f\u00fchren ;).<\/p>\n<p>Wer detaillierter einsteigen m\u00f6chte, sei auf das <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.0\/en\/create-trigger.html\">MySQL-Manual zu CREATE TRIGGER<\/a> verwiesen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ich finds sehr praktisch, direkt auf Datenbankseite soviel wie m\u00f6glich zu erledigen. Da wirds dann auch noch einen Artikel zu geben. Ich wurde neulich von Oracle inspiriert, wo folgende Konstrukte m\u00f6glich sind: create table Product ( ProdNr integer constraint PK_Product &hellip; <a href=\"https:\/\/d-mueller.de\/blog\/mysql-inputvalidierung-mit-triggern\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,3],"tags":[],"class_list":["post-449","post","type-post","status-publish","format-standard","hentry","category-datenbanken","category-webdev"],"_links":{"self":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/449","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/comments?post=449"}],"version-history":[{"count":0,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/449\/revisions"}],"wp:attachment":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/media?parent=449"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/categories?post=449"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/tags?post=449"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}