Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL: how to enforce that only a single column is set in a group of columns

In SQL, is there a way to enforce that only one column out of a group of columns has a value, and the others are null? Maybe a constraint or trigger? This type of thing might be for a lookup table, but are there any alternate table designs that might accomplish this better?

For example:

ID    OtherTable1ID    OtherTable2ID    OtherTable3ID
-----------------------------------------------------
1     23               NULL             NULL
2     NULL             45               NULL
3     33               55               NULL   -- NOT ALLOWED

The main issue is that these columns are all FKs to other tables, so I can't collapse them down to a single column.

I'm using SQL Server, but any answer will do.

like image 266
Andy White Avatar asked Jun 06 '09 21:06

Andy White


People also ask

How do I group just one column in SQL?

To arrange identical data into groups, we use SQL group by clause. The SQL group by single column clause places all the records having the same value of only a particular column into one group.

Which constraint can be enforced only one per table?

PRIMARY KEY constraint differs from the UNIQUE constraint in that; you can create multiple UNIQUE constraints in a table, with the ability to define only one SQL PRIMARY KEY per each table. Another difference is that the UNIQUE constraint allows for one NULL value, but the PRIMARY KEY does not allow NULL values.


3 Answers

@tvanfosson's suggested constraints work OK for three columns, but for generality I prefer

(cast(col1 is not null, int) +
 cast(col2 is not null, int) +
 cast(col3 is not null, int)) = 1

because it generalizes better to any number of columns with "linearly growing" (instead of "quadratically growing") amount of coding (it's even neater in SQL dialects that don't require explicit casting of boolean aka bit to int, but I'm not sure if SQL Server is one of those).

like image 93
Alex Martelli Avatar answered Nov 15 '22 16:11

Alex Martelli


A constraint such as the following should work:

 (column1 is null and column2 is null)
   or (column1 is null and column3 is null)
   or (column2 is null and column3 is null)

This won't force it to contain a non-null column, however. To do that add another constraint:

 column1 is not null
    or column2 is not null
    or column3 is not null
like image 23
tvanfosson Avatar answered Nov 15 '22 17:11

tvanfosson


CREATE TABLE Repro.Entity
(
    entityId INTEGER IDENTITY (1, 1) NOT NULL,
    column1 INTEGER,
    column2 INTEGER,
    column3 INTEGER,
    CONSTRAINT Entity_PK PRIMARY KEY(entityId),
    CONSTRAINT Entity_CK CHECK(
        (column1 IS NOT NULL AND column2 IS NULL AND column3 IS NULL) OR 
        (column1 IS NULL AND column2 IS NOT NULL AND column3 IS NULL) OR 
        (column1 IS NULL AND column2 IS NULL AND column3 IS NOT NULL))
)
like image 38
John Saunders Avatar answered Nov 15 '22 18:11

John Saunders