Periksa kendala hanya satu dari tiga kolom yang bukan nol

61

Saya memiliki tabel (SQL Server) yang berisi 3 jenis hasil: FLOAT, NVARCHAR (30), atau DATETIME (3 kolom terpisah). Saya ingin memastikan bahwa untuk setiap baris yang diberikan, hanya satu kolom yang memiliki hasil dan kolom lainnya adalah NULL. Apa kendala pemeriksaan paling sederhana untuk mencapai ini?

Konteks untuk ini adalah mencoba memperbaiki kemampuan untuk menangkap hasil non-numerik ke dalam sistem yang ada. Menambahkan dua kolom baru ke tabel dengan kendala untuk mencegah lebih dari satu hasil per baris adalah pendekatan yang paling ekonomis, tidak harus yang benar.

Pembaruan: Maaf, tipe data snafu. Sayangnya saya tidak bermaksud tipe hasil yang ditunjukkan ditafsirkan sebagai tipe data SQL Server, hanya istilah umum, diperbaiki sekarang.

David Clarke
sumber

Jawaban:

72

Yang berikut harus melakukan trik:

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
sumber
24

Anda mungkin perlu melakukan tiga tes dalam batasan, satu tes untuk setiap pasangan yang Anda inginkan menjadi nol dan satu untuk kolom yang seharusnya tidak nol:

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
sumber
Ini tidak begitu scalable, saya punya meja dengan 9 kunci asing dan hanya satu yang tidak boleh nol, saya lebih suka solusi
@MarkStoreySmith
5

Berikut ini adalah solusi PostgreSQL menggunakan fungsi array bawaan :

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
sumber
Apakah ini akan menjadi implementasi yang lebih cepat di postgreSQL daripada solusi KASUS atau DAN / ATAU yang disebutkan sebelumnya yang masing-masing diposting oleh Mark Storey dan mrdenny?
Chris Britt