Controlla il vincolo solo una delle tre colonne non è nulla


61

Ho una tabella (SQL Server) che contiene 3 tipi di risultati: FLOAT, NVARCHAR (30) o DATETIME (3 colonne separate). Voglio assicurarmi che per ogni data riga, solo una colonna abbia un risultato e le altre colonne siano NULL. Qual è il vincolo di controllo più semplice per raggiungere questo obiettivo?

Il contesto per questo sta cercando di aggiornare la capacità di acquisire risultati non numerici in un sistema esistente. L'aggiunta di due nuove colonne alla tabella con un vincolo per impedire più di un risultato per riga è stato l'approccio più economico, non necessariamente quello corretto.

Aggiornamento: mi dispiace, tipo di dati snafu. Purtroppo non intendevo che i tipi di risultato indicati fossero interpretati come tipi di dati di SQL Server, solo termini generici, risolti ora.

Risposte:


72

Quanto segue dovrebbe fare il trucco:

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

24

Probabilmente dovrai eseguire tre test all'interno del vincolo, un test per ogni coppia che vuoi essere nullo e uno per la colonna che non dovrebbe essere null:

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)
);

Non è così scalabile, ho una tabella con 9 chiavi esterne e solo una non dovrebbe essere nulla, preferisco la soluzione di @MarkStoreySmith
Amir Pashazadeh

5

Ecco una soluzione PostgreSQL che utilizza le funzioni di array integrate :

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);

Questa sarà un'implementazione più rapida in postgreSQL rispetto alle soluzioni CASE o AND / OR precedentemente menzionate, pubblicate rispettivamente da Mark Storey e mrdenny?
Chris Britt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.