Reputation: 57
I'm working on integrating data validation into a table schema in SQL Server 2014.
smoke
can contain 0 (non-smoker), 1 (smoker) or 9 (missing).cigarette
can be a value equal to or under 887, 888 (not applicable) or 999 (missing).I want SQL Server to throw an error if a value other then not-applicable (888) or missing (999) is inserted into cigarette
if smoking
contains 0 (non-smoker). How do I do this?
This is an example of what I have now:
CREATE TABLE [dbo].[CHECK_table]
(
[study_id] [smallint] NOT NULL,
[smoke] [smallint] NOT NULL,
[cigarettes] [smallint] NOT NULL,
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[CHECK_table] WITH CHECK
ADD CHECK (([smoke] = (0) OR ([smoke] = (1) OR [smoke] = (8)) OR [smoke] = (9)))
GO
ALTER TABLE [dbo].[CHECK_table] WITH CHECK
ADD CHECK (([cigarettes] <= (90) OR [cigarette] = (888) OR [cigarette] = (999)))
GO
Upvotes: 0
Views: 210
Reputation: 3170
As expressed in one of the comments, Why not just let them be NULL
for unknown data? If you use a nullable bit field, you can get the same amount of detail you'd get by your scheme, with better storage and performance, and no need to enforce any constraints.
My suggestion:
CREATE TABLE #CHECK_table(
[study_id] [smallint] NOT NULL,
[smoke] [bit] NULL,
[cigarettes] [smallint] NULL ,
check (( case when [smoke] = 0 then 0 else 1 end ) = 1)
)
insert into #check_table ( study_id, smoke, cigarettes ) select 1, 1, 12
insert into #check_table ( study_id, smoke, cigarettes ) select 1, 0, 12
insert into #check_table ( study_id, smoke, cigarettes ) select 1, 1, null
The second insert there will fail with an error about the insert conflicting with the check constraint.
(aside: And also, why are you using smallint
- do you not expect to see very many records?)
add:
For export, when doing your final select from your table (as above), you could do:
select [study_id],
cast(case when [smoke] is null then 9 else [smoke] end as smallint) as [smoke],
[cigarettes]
from #CHECK_table
That way, you'd have clean data in your tables, without any codification. From a data standpoint, it's much clearer what you're seeing when you look at a bit column - it's either yes, no, or hasn't been answered. This also means that it's clear, when looking through the code, exactly that you've been codifying the data as well as how you've codified it.
Upvotes: 1
Reputation: 176214
You could use CASE
and replace multiple OR
to IN
:
CREATE TABLE #CHECK_table(
[study_id] [smallint] NOT NULL,
[smoke] [smallint] NOT NULL,
[cigarettes] [smallint] NOT NULL
);
ALTER TABLE #CHECK_table
WITH CHECK ADD CHECK ([smoke] IN (0,1,9));
ALTER TABLE #CHECK_table
WITH CHECK ADD CHECK (((CASE WHEN [smoke] = 0 AND [cigarettes] IN(999,888) THEN 1
WHEN [smoke] <> 0 AND ([cigarettes] <= 888
OR [cigarettes] = 999) THEN 1
ELSE 0 END) = 1)
);
Upvotes: 1