Überprüfen Sie die Einschränkung, dass nur eine der drei Spalten nicht null ist

61

Ich habe eine (SQL Server-) Tabelle, die drei Arten von Ergebnissen enthält: FLOAT, NVARCHAR (30) oder DATETIME (3 separate Spalten). Ich möchte sicherstellen, dass für eine bestimmte Zeile nur eine Spalte ein Ergebnis hat und die anderen Spalten NULL sind. Was ist die einfachste Prüfbedingung, um dies zu erreichen?

Der Kontext hierfür ist der Versuch, die Fähigkeit zur Erfassung nicht numerischer Ergebnisse in einem vorhandenen System nachzurüsten. Das Hinzufügen von zwei neuen Spalten zur Tabelle mit einer Einschränkung, um mehr als ein Ergebnis pro Zeile zu verhindern, war der wirtschaftlichste Ansatz, nicht unbedingt der richtige.

Update: Sorry, Datentyp snafu. Leider hatte ich nicht die Absicht, die angegebenen Ergebnistypen als SQL Server-Datentypen zu interpretieren, sondern nur als allgemeine Begriffe, die jetzt behoben wurden.

David Clarke
quelle

Antworten:

72

Folgendes sollte den Trick machen:

CREATE TABLE MyTable (col1 FLOAT NULL, col2 NVARCHAR(30) NULL, col3 DATETIME NULL);
GO

ALTER TABLE MyTable
ADD CONSTRAINT CheckOnlyOneColumnIsNull
CHECK 
(
    ( CASE WHEN col1 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col2 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col3 IS NULL THEN 0 ELSE 1 END
    ) = 1
)
GO
Mark Storey-Smith
quelle
24

Sie müssen wahrscheinlich drei Tests innerhalb der Einschränkung durchführen, einen Test für jedes Paar, das Sie als Nullwert festlegen möchten, und einen Test für die Spalte, die nicht als Nullwert festgelegt werden soll:

ALTER TABLE table
ADD CONSTRAINT CK_one_is_null
CHECK (
     (col1 IS NOT NULL AND col2 IS NULL AND col3 IS NULL)
  OR (col2 IS NOT NULL AND col1 IS NULL AND col3 IS NULL) 
  OR (col3 IS NOT NULL AND col1 IS NULL AND col2 IS NULL)
);
mrdenny
quelle
Dies ist nicht so skalierbar, ich habe eine Tabelle mit 9 Fremdschlüsseln und nur einer sollte nicht null sein, ich bevorzuge @MarkStoreySmiths Lösung
Amir Pashazadeh
5

Hier ist eine PostgreSQL-Lösung mit den integrierten Array-Funktionen :

ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK (array_length(array_remove(ARRAY[col1::text, col2::text, col3::text], NULL), 1) = 1);
CrEOF
quelle
Wird dies eine schnellere Implementierung in PostgreSQL sein als die zuvor erwähnten CASE- oder AND / OR-Lösungen von Mark Storey bzw. Mrdenny?
Chris Britt