Reputation: 3761
In Transact-SQL, what's the best way to compare two bit values that can be 0, 1, or NULL?
For example, in stored procedure that UPDATEs a bit column with a parameter value, I'd like to only perform the update if the parameter value is different from the value in the table (the values in the table and the parameter can be 0, 1 or NULL).
I'm considering:
WHERE …
AND (CASE WHEN b=@b OR COALESCE(b,@b) IS NULL THEN 0 ELSE 1 END) = 1
vs.
WHERE …
AND EXISTS (SELECT b EXCEPT SELECT @b)
Is there a good reason to prefer one over the other? Is there a better way to do this?
In this case, only one row will be updated, so I don't think performance is a big issue, unless there's a large difference.
Upvotes: 0
Views: 215
Reputation: 15816
Since the data being compared are nullable bit
values you can use Coalesce( B, -1 ) = Coalesce( @B, -1 )
to perform matching of all three values (0
, 1
and NULL
) by mapping them to 0
, 1
and -1
.
Coalesce
follows the rules for data type precedence. Given a bit
(B
) and an int
(-1
) it will convert the bit
to an int
so that the result is an int
value.
The expression is not SARGable, but in this case the OP has stated that the operation is being performed on a single row already identified by PK so the performance of the comparison is not significant.
Note that this is a case of introducing a value (-1
) that cannot occur in the original data's data type (bit
). It is not the same as picking an arbitrary magic value that probably won't occur, e.g. the year 1800
is much too far in the past to ever turn up in a DateSold
column. Except for real estate and various other things.
Bonus tip:
A handy way to confirm the behavior is by using SQL_Variant_Property
to display the data type of the result:
declare @B as Bit = 1;
select SQL_Variant_Property( Coalesce( @B, -1 ), 'BaseType' );
Upvotes: 1