Home All Groups Group Topic Archive Search About

==again== constraints with nulls

Author
16 Dec 2005 6:35 PM
sqlster
I posted this question yesterday with out good table structure and sample data
http://www.microsoft.com/technet/community/newsgroups/dgbrowser/en-us/default.mspx?query=sqlster&dg=microsoft.public.sqlserver.programming&cat=en-us-technet-sqlserv&lang=en&cr=US&pt=261BA873-F3AB-420E-96D6-E3004596A551&catlist=328BAFD2-1A81-4558-B1DE-B6EB49F31B7E&dglist=&ptlist=&exp=&sloc=en-us

Thanks Aaron and Celko for addressing it yesterday.

I am posting the question again with ddl and sample data

use testdb
go
set nocount on
go
create table mytbl
(
    pkid int not null identity(1,1) primary key,
    d1 int not null unique,
    c1 int null,
    c2 int null,
    c3 int null,
    okay varchar(10) -- indicates whether row is valid
)
go
insert into mytbl(d1,c1,c2,c3,okay)
select 1,11,2,3,'yes' union
select 2,21,5,6,'yes' union
select 3,23,23,7,'no' union
select 4,99,99,99,'no' union
select 5,8,7,7,'no' union
select 6,null,null,null,'yes' union
select 7,null,null,null,'yes' union
select 8,9,7,9,'no' union
select 9,19,null,null,'yes' union
select 10,99,7,null,'yes'

go
select * from mytbl
go
/*
pkid        d1          c1          c2          c3          okay      
----------- ----------- ----------- ----------- ----------- ----------
1           1           11          2           3           yes
2           2           21          5           6           yes
3           3           23          23          7           no
4           4           99          99          99          no
5           5           8           7           7           no
6           6           NULL        NULL        NULL        yes
7           7           NULL        NULL        NULL        yes
8           8           9           7           9           no
9           9           19          NULL        NULL        yes
10          10          99          7           NULL        yes
*/
drop table mytbl
go

How could I create constraint such that for a given unique d1; c1,c2,and c3
would be unique and still allow all nulls. Okay column in sample results
indicate yes and no for the allowed and disallowed row. I hope this made it
clear.

Please help me with the constraint and thank you again for addressing it.

Author
16 Dec 2005 6:55 PM
Alexander Kuznetsov
well this passed your test harness

create table #mytbl
(
        pkid int not null identity(1,1) primary key,
        d1 int not null unique,
        c1 int null,
        c2 int null,
        c3 int null,
        okay varchar(10), -- indicates whether row is valid ,
check(not((c1=c2)or(c1=c3)or(c2=c3)))
)
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 1,11,2,3,'yes'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 2,21,5,6,'yes'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 3,23,23,7,'no'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 4,99,99,99,'no'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 5,8,7,7,'no'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 6,null,null,null,'yes'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 7,null,null,null,'yes'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 8,9,7,9,'no'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 9,19,null,null,'yes'
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 10,99,7,null,'yes'

go
select * from #mytbl
go
drop table #mytbl
Author
16 Dec 2005 7:00 PM
Trey Walpole
ahh - c1,c2 and c3 cannot equal each other..

are there disallowed values for these columns? (e.g., c1,c2 & c3 cannot
be negative)?
what you need for this is a check constraint, not a unique constraint. -
  a unique constraint applies to rows, but you can create a check
constraint to apply to columns

e.g. (-1 being an "impossible" values)
  create table mytbl
  (
      pkid int not null identity(1,1) primary key,
      d1 int not null unique,
      c1 int null,
      c2 int null,
      c3 int null,
      okay varchar(10), -- indicates whether row is valid
CHECK (coalesce(c1,-1) <> coalesce(c2,-2) and coalesce(c2,-1) <>
coalesce(c3,-3))
  )



sqlster wrote:
Show quote
> I posted this question yesterday with out good table structure and sample data
>
> http://www.microsoft.com/technet/community/newsgroups/dgbrowser/en-us/default.mspx?query=sqlster&dg=microsoft.public.sqlserver.programming&cat=en-us-technet-sqlserv&lang=en&cr=US&pt=261BA873-F3AB-420E-96D6-E3004596A551&catlist=328BAFD2-1A81-4558-B1DE-B6EB49F31B7E&dglist=&ptlist=&exp=&sloc=en-us
>
> Thanks Aaron and Celko for addressing it yesterday.
>
> I am posting the question again with ddl and sample data
>
> use testdb
> go
> set nocount on
> go
> create table mytbl
> (
>     pkid int not null identity(1,1) primary key,
>     d1 int not null unique,
>     c1 int null,
>     c2 int null,
>     c3 int null,
>     okay varchar(10) -- indicates whether row is valid
> )
> go
> insert into mytbl(d1,c1,c2,c3,okay)
> select 1,11,2,3,'yes' union
> select 2,21,5,6,'yes' union
> select 3,23,23,7,'no' union
> select 4,99,99,99,'no' union
> select 5,8,7,7,'no' union
> select 6,null,null,null,'yes' union
> select 7,null,null,null,'yes' union
> select 8,9,7,9,'no' union
> select 9,19,null,null,'yes' union
> select 10,99,7,null,'yes'
>
> go
> select * from mytbl
> go
> /*
> pkid        d1          c1          c2          c3          okay      
> ----------- ----------- ----------- ----------- ----------- ----------
> 1           1           11          2           3           yes
> 2           2           21          5           6           yes
> 3           3           23          23          7           no
> 4           4           99          99          99          no
> 5           5           8           7           7           no
> 6           6           NULL        NULL        NULL        yes
> 7           7           NULL        NULL        NULL        yes
> 8           8           9           7           9           no
> 9           9           19          NULL        NULL        yes
> 10          10          99          7           NULL        yes
> */
> drop table mytbl
> go
>
> How could I create constraint such that for a given unique d1; c1,c2,and c3
> would be unique and still allow all nulls. Okay column in sample results
> indicate yes and no for the allowed and disallowed row. I hope this made it
> clear.
>
> Please help me with the constraint and thank you again for addressing it.
Author
16 Dec 2005 7:53 PM
Mark Williams
An INSERT or UPDATE is allowed on a table with a CHECK constraint if the
condition evaluates to TRUE or UNKNOWN. The statement NULL = NULL evaluates
to UNKNOWN, so multiple NULLs in c1, c2, and c3 would pass the check
constraint.

CHECK(c1<>c2 AND c1<>c3 AND c2<>c3)

For a row with c1, c2, and c3 of 23, 23, and NULL you get

CHECK(FALSE AND UNKNOWN AND UNKNOWN)

Ternary logic rules state FALSE AND UNKNOWN = FALSE, so the overall CHECK
constraint returns FALSE, and the row would not be allowed.

If you went with
CHECK(NOT(c1=c2 OR c1=c3 OR c2=c3))

The row 23, 23, NULL would go through this logic

CHECK(NOT(TRUE OR UNKNOWN OR UNKNOWN))
CHECK(NOT(TRUE))
CHECK(FALSE)


Show quote
"sqlster" wrote:

> I posted this question yesterday with out good table structure and sample data
>
> http://www.microsoft.com/technet/community/newsgroups/dgbrowser/en-us/default.mspx?query=sqlster&dg=microsoft.public.sqlserver.programming&cat=en-us-technet-sqlserv&lang=en&cr=US&pt=261BA873-F3AB-420E-96D6-E3004596A551&catlist=328BAFD2-1A81-4558-B1DE-B6EB49F31B7E&dglist=&ptlist=&exp=&sloc=en-us
>
> Thanks Aaron and Celko for addressing it yesterday.
>
> I am posting the question again with ddl and sample data
>
> use testdb
> go
> set nocount on
> go
> create table mytbl
> (
>     pkid int not null identity(1,1) primary key,
>     d1 int not null unique,
>     c1 int null,
>     c2 int null,
>     c3 int null,
>     okay varchar(10) -- indicates whether row is valid
> )
> go
> insert into mytbl(d1,c1,c2,c3,okay)
> select 1,11,2,3,'yes' union
> select 2,21,5,6,'yes' union
> select 3,23,23,7,'no' union
> select 4,99,99,99,'no' union
> select 5,8,7,7,'no' union
> select 6,null,null,null,'yes' union
> select 7,null,null,null,'yes' union
> select 8,9,7,9,'no' union
> select 9,19,null,null,'yes' union
> select 10,99,7,null,'yes'
>
> go
> select * from mytbl
> go
> /*
> pkid        d1          c1          c2          c3          okay      
> ----------- ----------- ----------- ----------- ----------- ----------
> 1           1           11          2           3           yes
> 2           2           21          5           6           yes
> 3           3           23          23          7           no
> 4           4           99          99          99          no
> 5           5           8           7           7           no
> 6           6           NULL        NULL        NULL        yes
> 7           7           NULL        NULL        NULL        yes
> 8           8           9           7           9           no
> 9           9           19          NULL        NULL        yes
> 10          10          99          7           NULL        yes
> */
> drop table mytbl
> go
>
> How could I create constraint such that for a given unique d1; c1,c2,and c3
> would be unique and still allow all nulls. Okay column in sample results
> indicate yes and no for the allowed and disallowed row. I hope this made it
> clear.
>
> Please help me with the constraint and thank you again for addressing it.
Author
16 Dec 2005 8:18 PM
Alexander Kuznetsov
> If you went with
> CHECK(NOT(c1=c2 OR c1=c3 OR c2=c3))
> The row 23, 23, NULL would go through this logic

Mark,

I don't see it happening:

create table #mytbl
(
        pkid int not null identity(1,1) primary key,
        d1 int not null unique,
        c1 int null,
        c2 int null,
        c3 int null,
        okay varchar(10), -- indicates whether row is valid ,
check(not((c1=c2)or(c1=c3)or(c2=c3)))
)
go
insert into #mytbl(d1,c1,c2,c3,okay)
select 9,19,19,null,'yes'

Server: Msg 547, Level 16, State 1, Line 1
INSERT statement conflicted with TABLE CHECK constraint
'CK__#mytbl__060958A8'. The conflict occurred in database 'tempdb',
table
'#mytbl______________________________________________________________________________________________________________000000000451'.
The statement has been terminated.


go
select * from #mytbl

pkid        d1          c1          c2          c3          okay
----------- ----------- ----------- ----------- ----------- ----------

(0 row(s) affected)

go
drop table #mytbl
Author
16 Dec 2005 8:50 PM
Mark Williams
Sorry, I didn't mean that the row would "go through" or pass the check
constraint.
I meant that the logic flow would be as I demonstrated.

With the row that you tried inserting, you would check

CHECK(NOT((19=19) OR (19=NULL) OR (19=NULL))
CHECK(NOT(TRUE OR UNKNOWN OR UNKNOWN))
CHECK(NOT(TRUE))
CHECK(FALSE)

The insert would fail.


Show quote
"Alexander Kuznetsov" wrote:

> > If you went with
> > CHECK(NOT(c1=c2 OR c1=c3 OR c2=c3))
> > The row 23, 23, NULL would go through this logic
>
> Mark,
>
> I don't see it happening:
>
> create table #mytbl
> (
>         pkid int not null identity(1,1) primary key,
>         d1 int not null unique,
>         c1 int null,
>         c2 int null,
>         c3 int null,
>         okay varchar(10), -- indicates whether row is valid ,
> check(not((c1=c2)or(c1=c3)or(c2=c3)))
> )
> go
> insert into #mytbl(d1,c1,c2,c3,okay)
> select 9,19,19,null,'yes'
>
> Server: Msg 547, Level 16, State 1, Line 1
> INSERT statement conflicted with TABLE CHECK constraint
> 'CK__#mytbl__060958A8'. The conflict occurred in database 'tempdb',
> table
> '#mytbl______________________________________________________________________________________________________________000000000451'.
> The statement has been terminated.
>
>
> go
> select * from #mytbl
>
> pkid        d1          c1          c2          c3          okay
> ----------- ----------- ----------- ----------- ----------- ----------
>
> (0 row(s) affected)
>
> go
> drop table #mytbl
>
>
Author
18 Dec 2005 2:57 AM
Alexander Kuznetsov
Mark,

no problem. Sorry I misunderstood you
Author
16 Dec 2005 11:27 PM
Brian Selzer
It sounds like what you may need is an ANSI unique constraint.  SQL Server
UNIQUE and PRIMARY KEY constraints treat NULLs as a value, and only allow
one instance to occur.  The following link shows several methods you can use
to implement an ANSI unique constraint, which allows duplicate NULL values.
My preference is the view method.

http://support.microsoft.com/default.aspx?scid=kb;en-us;322002

Show quote
"sqlster" <nospam@nospam.com> wrote in message
news:7E90E887-E3E5-46FD-A875-6229F7B447CC@microsoft.com...
>I posted this question yesterday with out good table structure and sample
>data
>
> http://www.microsoft.com/technet/community/newsgroups/dgbrowser/en-us/default.mspx?query=sqlster&dg=microsoft.public.sqlserver.programming&cat=en-us-technet-sqlserv&lang=en&cr=US&pt=261BA873-F3AB-420E-96D6-E3004596A551&catlist=328BAFD2-1A81-4558-B1DE-B6EB49F31B7E&dglist=&ptlist=&exp=&sloc=en-us
>
> Thanks Aaron and Celko for addressing it yesterday.
>
> I am posting the question again with ddl and sample data
>
> use testdb
> go
> set nocount on
> go
> create table mytbl
> (
> pkid int not null identity(1,1) primary key,
> d1 int not null unique,
> c1 int null,
> c2 int null,
> c3 int null,
> okay varchar(10) -- indicates whether row is valid
> )
> go
> insert into mytbl(d1,c1,c2,c3,okay)
> select 1,11,2,3,'yes' union
> select 2,21,5,6,'yes' union
> select 3,23,23,7,'no' union
> select 4,99,99,99,'no' union
> select 5,8,7,7,'no' union
> select 6,null,null,null,'yes' union
> select 7,null,null,null,'yes' union
> select 8,9,7,9,'no' union
> select 9,19,null,null,'yes' union
> select 10,99,7,null,'yes'
>
> go
> select * from mytbl
> go
> /*
> pkid        d1          c1          c2          c3          okay
> ----------- ----------- ----------- ----------- ----------- ----------
> 1           1           11          2           3           yes
> 2           2           21          5           6           yes
> 3           3           23          23          7           no
> 4           4           99          99          99          no
> 5           5           8           7           7           no
> 6           6           NULL        NULL        NULL        yes
> 7           7           NULL        NULL        NULL        yes
> 8           8           9           7           9           no
> 9           9           19          NULL        NULL        yes
> 10          10          99          7           NULL        yes
> */
> drop table mytbl
> go
>
> How could I create constraint such that for a given unique d1; c1,c2,and
> c3
> would be unique and still allow all nulls. Okay column in sample results
> indicate yes and no for the allowed and disallowed row. I hope this made
> it
> clear.
>
> Please help me with the constraint and thank you again for addressing it.

AddThis Social Bookmark Button