2016-08-20 1 views
3

Ich bereite mich auf eine Prüfung auf Model-Driven Development vor. Ich stieß auf eine bestimmte Datenbank-Trigger:Datenbankauslöser: Vergleich von Spaltenwert mit leerer Variable

CREATE TRIGGER tManager_bi 
FOR Manager BEFORE INSERT AS 
DECLARE VARIABLE v_company_name CHAR(30); 
BEGIN 
    SELECT M.company 
    FROM Manager M 
    WHERE M.nr = NEW.reports_to 
    INTO :v_company_name; 

    IF (NOT(NEW.company = v_company_name)) 
    THEN EXCEPTION eReportsNotOwnCompany; 
END 

Dieser Trigger ausgelegt Eingang ein Manager Berichte an einen externen Manager, in dem zu verhindern, das heißt eine, die nicht von der gleichen Firma ist. Die entsprechende OCL-Einschränkung ist:

context Manager 
    inv: self.company = self.reports_to.company 

Die entsprechende Tabelle wie (vereinfacht) aussieht:

CREATE TABLE Manager 
(
    nr INTEGER NOT NULL, 
    company VARCHAR(50) NOT NULL, 
    reports_to INTEGER, 
    PRIMARY KEY (nr), 
    FOREIGN KEY (reports_to) REFERENCES Manager (nr) 
); 

Das Lehrbuch sagt, dass dieser Trigger auch korrekt funktionieren, wenn die neu eingefügten Manager nicht zu niemandem berichten (dh NEW.reports_to ist NULL), und tatsächlich funktioniert es nach dem Testen richtig.

Aber ich verstehe das nicht. Wenn NEW.reports_toNULL ist, würde das bedeuten, dass die Variable v_company_name leer ist (nicht initialisiert? NULL?), Was dann bedeuten würde, dass der Vergleich false zurückgeben würde, wodurch die Ausnahme ausgelöst würde, richtig?

Was fehlt mir hier?

(Die SQL SQL gezeigt werden soll:.. 2003 konform Das MDD-Werkzeug Cathedron ist, die als RDBMS Firebird verwendet)

+1

_ "Dieser Trigger ausgebildet ist Eingabe zu verhindern, in dem ein Manager berichtet sich selbst. "Bist du sicher? Dieser Trigger scheint geschrieben zu sein, um Eingaben zu verhindern, in denen ein Manager einem anderen Unternehmen berichtet. – pilcrow

+0

@pilcrow Guter Fang! Bearbeitet. –

Antwort

6

Sie verpassen die Tatsache, dass, wenn Sie vergleichen NULL-NULL (oder zu jedem anderen Wert), ist die Antwort NULL, nicht false. Und die Negation von NULL ist immer noch NULL, also würde in der IF Aussage der ELSE Teil feuern (wenn es einen gibt).

Ich schlage vor, Sie lesen die Firebird Null Guide zum besseren Verständnis alles.

+0

Also, nur um sicher zu sein: der Wert, der in die Variable 'v_company_name' nach der Auswahl, die eine leere Tabelle zurückgibt, ist 'NULL', nicht irgendeine (andere) Art von undefiniertem Wert? –

+1

Wenn die Select-Anweisung ein leeres Resultset zurückgibt, bleibt der Wert des 'v_Company_Name' unverändert (er ist nicht auf NULL gesetzt!). Es hätte also den Wert, den es hatte, bevor die SELECT-Anweisung ausgeführt wurde, die in diesem Fall NULL sein sollte. – ain

+0

Sie haben absolut Recht.Von Ihrem Link: "Wenn Sie eine Variable in einer gespeicherten Prozedur oder einem Trigger deklarieren, ist ihr Wert nicht definiert und ihr Status ist vom Zeitpunkt der Erstellung an" NULL ", bis ein Wert zugewiesen wird." –

2

AS. Diese Antwort aus Gründen der Code-Hervorhebung machen.

Möglicherweise möchten Sie Ihren Auslöser so ändern, dass er sowohl auf Aktualisierungen als auch auf Einfügungen reagiert.

Sie können auch vermeiden, den Auslöser überhaupt handschriftlich zu schreiben, wenn Sie diese spezielle Ausnahmekennung nicht benötigen.

Sie können nur SQL Check Constraint für diese Verwendung

alter table Manager 
    add constraint chk_ManagerNotRespondsOneself 
     CHECK (NOT EXISTS (
      SELECT * FROM Manager M 
      WHERE M.nr = reports_to 
      AND M.company = company 
     )) 

Festlegen des benutzerdefinierten Ausnahmen über CHECK-Einschränkungen jetzt nicht möglich aussehen ... http://tracker.firebirdsql.org/browse/CORE-1852

Verwandte Themen