This seems easy at first but after thinking about it for the day I’m stuck.
Imagine you have a global block list for veggies.
create table blocked_veggie(veggieid int primary key, veggiename varchar(20)) insert into blocked_veggie(veggieid, veggiename) values(1, 'broccoli') insert into blocked_veggie(veggieid, veggiename) values(2, 'carrots')
This table says these veggies are never allowed at dinner.
However, there is also an override table for a specific child that says for this child ignore the global block and allow the veggie.
create table allow_veggie(allowuid uniqueidentifier primary key, veggiename varchar(20), childname varchar(20)) insert into allow_veggie(allowuid, veggiename, childname) values(newid(), 'broccoli', 'Jimmy')
Here is what the query looks like:
declare @veggie varchar(20) = 'broccoli' , @childname varchar(20) = 'Jimmy' select 1 from blocked_veggie v where v.veggiename = @veggie union all select 1 from allow_veggie a where a.veggiename = @veggie and a.childname = @childname
How can I cancel out the first query where I find a hit in the second query? Put another way I would want an empty result set returned.
I can’t combine them because I could have this scenario…
declare @veggie varchar(20) = 'broccoli' , @childname varchar(20) = null select 1 from blocked_veggie v where v.veggiename = @veggie union all select 1 from allow_veggie a where a.veggiename = @veggie and a.childname = @childname
Here there is no childname so there is not override of the global block.
Advertisement
Answer
I think we should use EXCEPT
here, rather than UNION
.
declare @veggie varchar(20) = 'broccoli', @childname varchar(20) = 'Jimmy'; select v.veggiename from blocked_veggie v where v.veggiename = @veggie EXCEPT select a.veggiename from allow_veggie a where a.veggiename = @veggie and a.childname = @childname ;
If a @childname
is NULL, the second part of the query would return no rows, because a.childname = NULL
is false, and the overall query will return all rows from blocked_veggie
.