2012-04-23 7 views
20


Ich bin neugierig zu wissen, ist es möglich, eine bedingte Nicht-Null-Einschränkung in SQL zu erstellen? Mit anderen Worten ist es möglich, eine Einschränkung zu erzeugen, so dass eine Spalte B null sein kann, solange Spalte A enthält, sagen wir "NEW", aber wenn der Inhalt von Spalte A sich zu etwas anderem ändert, dann darf Spalte B nicht länger Null sein?
Und um darauf zu erweitern, ist es dann möglich, es so zu machen, dass Spalte B null oder leer sein muss, solange Spalte A "NEU" sagt? Alle
Dank: D
Sql Conditional Nicht Null Constraint

+0

FWIW, glaube ich nicht, die meisten Datenbank-Designer dies eine bedingte Einschränkung nennen würde. * Ich würde * wahrscheinlich nur eine Einschränkung nennen, aber wenn ich es mehr qualifizieren müsste, könnte ich es eine mehrspaltige Einschränkung oder eine mehrspaltige CHECK() - Einschränkung nennen. Es ist Standard SQL. –

+0

@Catcall: Chris Datum Zitat: "solche Einschränkungen werden gelegentlich informell als Tupel-Einschränkungen oder Zeileneinschränkungen in SQL bezeichnet - obwohl dieser letztere Begriff auch in SQL verwendet wird, um genauer zu sein, eine Zeileneinschränkung, die nicht möglich ist als Spaltenbeschränkung formuliert werden ... Alle diese Verwendungen sind jedoch veraltet, da Einschränkungen Aktualisierungen einschränken und ... in der relationalen Welt gibt es keine Aktualisierung von Tupeln oder Zeilen. " – onedaywhen

+0

@onedaywhen: Ich habe die aktuelle Ausgabe nicht. In der 7. Ausgabe sieht das, was ich hier sehe (abgesehen von NULL), so aus, wie er es nennt, eine Relvar-Einschränkung (p253).Es nimmt mehrere Spalten auf, und er sagt, dass es beliebig komplex sein kann (was bedeutet, dass es sich auf andere Beziehungen, Ansichten, Aggregate und Phasen des Mondes beziehen könnte). –

Antwort

23

Dies ist völlig in Ordnung für CONSTRAINT CHECK. Genau dies tut:

Voraussetzung:

ist es möglich, eine Einschränkung, so dass eine Spalte B erstellen so lange Spalte A enthält können sagen, ‚NEW‘ aber, wenn der Inhalt der Spalte A null sein Änderungen an etwas anderem, dann darf Spalte B nicht mehr null sein?

Hinweis der Satz:

create table tbl 
(
    A varchar(10) not null, 
    B varchar(10), 

    constraint uk_tbl check 
    (
     A = 'NEW' -- B can be null or not null: no need to add AND here 
     OR (A <> 'NEW' AND B IS NOT NULL) 
    ) 
); 

Sie können es weiter vereinfachen:

create table tbl 
(
    A varchar(10) not null, 
    B varchar(10), 

    constraint uk_tbl check 
    (
     A = 'NEW' 
     OR B IS NOT NULL 
    ) 
); 

Anforderung miteinander unverträgliche Spalte B kann

Lösung null sein oben auf Anforderung:

Und das zu verlängern, ist es dann möglich, dass die Spalte B macht so null sein muss, oder so lange leer, wie Spalte A ‚NEW‘ sagt?

Notiere die Phrase: Spalte B must null

create table tbl 
(
    A varchar(10) not null, 
    B varchar(10), 

    constraint uk_tbl check 
    (
     (A = 'NEW' AND B IS NULL) 
     OR A <> 'NEW' 
    ) 
); 

Könnte dies vereinfacht werden, einfacher, aber vielleicht nicht so lesbar wie oben sein, aber:

create table tbl 
(
    A varchar(10) not null, 
    B varchar(10), 

    constraint uk_tbl check 
    (
     A <> 'NEW' 
     OR B IS NULL 
    ) 
); 
+3

Ich glaube, das einzige moderne SQL-DBMS, an dem * nicht gearbeitet wird, ist MySQL. MySQL erzwingt CHECK() - Einschränkungen nicht. (Frage ist mit "SQL" markiert, daher schien ein Kommentar relevant.) –

+0

Ich folgere nur, dass er Sql Server benutzt, ich habe einige seiner Fragen überprüft. Die meisten Datenbankfragen sind nicht spezifisch markiert und sollten auch nicht sein. Wenn möglich, möchte ich stackoverflow sql-Tag nicht akzeptieren, so dass jeder spezifischer sein könnte, welche RDBMS sie verwenden –

+0

Diese Einschränkungsprüfung funktioniert bereits seit Tag 1 auf Sql Server, ebenfalls auf Postgresql. Ich testete diese DDL sowohl auf SQL Server als auch auf PostgreSQL, beide akzeptieren sie –

0

Per onedaywhen, diese Antwort sträflich falsch ist, und ein Greuel. Sie können eine CHECK Einschränkung verwenden. http://msdn.microsoft.com/en-us/library/ms188258.aspx

Es gibt keine Möglichkeit, bedingte Einschränkungen zu erstellen. Sie sollten jedoch in der Lage sein, den Job mit einem Trigger zu erledigen. Dafür sind sie da.

http://msdn.microsoft.com/en-us/library/ms189799.aspx

CREATE TRIGGER MyTable.ConditionalNullConstraint ON MyTable.ColumnB 
AFTER INSERT 
AS 
IF EXISTS (SELECT * 
    FROM inserted 
    WHERE A <> 'NEW' AND B IS NULL 
    ) 
BEGIN 
    RAISERROR ('if A is ''NEW'' then B cannot be NULL', 16, 1); 
    ROLLBACK TRANSACTION; 
END; 
GO 

Hinweis in der Abfrage, dass Sie eingefügt verweisen werden wollen, die ein spezielles Objekt, das wie ein Tisch verhält, und können Sie die Zeile referenzieren (en), die den Auslöser verursacht .

Natürlich müssten Sie in diesem Beispiel NACH AKTUALISIEREN auch die Einschränkung zu erzwingen, aber das ist die allgemeine Idee.

+0

"Es gibt keine Möglichkeit bedingte Einschränkungen zu machen" Huh? Dies kann durch eine Tupel-Einschränkung ('CHECK') gehandhabt werden und sollte in diesem Fall einem Trigger vorgezogen werden. – onedaywhen

+0

@onedaywenn wow, ich stehe sehr korrigiert, danke. Überprüfen Sie die Einschränkung: http://msdn.microsoft.com/en-us/library/ms188258.aspx – McGarnagle

1

Edit: wie in den anderen Antworten erwähnt, ist ein CHECK die beste Methode, nicht der Auslöser, den ich ursprünglich vorgeschlagen habe. Ursprünglicher Text folgt:


Wie dbaseman schon sagt, Auslöser sind die Art und Weise zu gehen (nicht so). Versuchen Sie so etwas (nicht getestet):

CREATE OR REPLACE TRIGGER test 
    BEFORE UPDATE ON table1 
FOR EACH ROW 
WHEN (new.A = 'NEW' and new.B IS NOT NULL) 
    RAISE_APPLICATION_ERROR (
    num=> -20001, 
    msg=> 'B must be NULL for new rows (A = NEW)' 
); 
+0

Aus Gründen der Übersichtlichkeit ist diese Lösung für Oracle. DBaseman bietet eine Lösung für das, was ich als MSSQL voraussetze :) – dwurf

+0

Oracle unterstützt Tuple-Constraints ('CHECK'): deklarative Constraints sollten über dem prozeduralen Code (einschließlich Trigger) gewählt werden. – onedaywhen

1

Ich denke, Ihre erste angegebene Anforderung lautet:

IF (B IS NULL) THEN (A = 'NEW') 

die Implikation Rewrite-Regel anwenden:

IF (X) THEN (Y) <=> (NOT (X) OR (Y)) 

In Ihrem Fall;

(NOT (B IS NULL) OR (A = 'NEW')) 

Minor Rewrite Vorteil von SQL-Syntax zu nehmen:

(B IS NOT NULL OR A = 'NEW') 

Ihre Sekunde angegeben ("verlängern") Voraussetzung:

IF (A = 'NEW') THEN (B IS NULL) 

Rewrite-Regel anwenden:

(NOT (A = 'NEW') OR (B IS NULL)) 

Minor Rewrite:

(A <> 'NEW' OR B IS NULL)