SQL Server – Nullable Result in Deterministic CASE in View

computed-columnnullsql serversql-server-2016view

I have a table, with Id as the primary key.

create table Anything
(
    Id bigint not null primary key identity(1, 1)
)

When I look at this table in Object Explorer, I see this image of course:

Enter image description here

As you can see, column Id is not null.

Then I create a dummy view on this dummy table:

create view IdIsTwoView
as

select
    Id,
    (
        case
        when Id = 2
        then cast(1 as bit)
        else cast(0 as bit)
        end
    ) as IdIsTwo
from Anything

But this time, in Object Explorer I see this result:

Enter image description here

As you can see, in spite of this fact that my case clause is all-encompassing and covers 100% of all records, and has an answer for all records, it's nullable.

Why does SQL Server have this weird behavior? And how do I force it to be not null?

P.S we have an infrastructure to generate code dynamically, and this behavior causes us trouble and we have to manually go and change all bool? types in C# to bool.

Best Answer

To answer the why part of your question, the CASE expression result is nullable because the CAST function result is nullable. This can be observed with:

EXEC sp_describe_first_result_set N'SELECT CAST(1 AS bit) AS result;';

Result (abbreviated):

+-----------+----------------+--------+-------------+----------------+------------------+
| is_hidden | column_ordinal |  name  | is_nullable | system_type_id | system_type_name |
+-----------+----------------+--------+-------------+----------------+------------------+
|         0 |              1 | result |           1 |            104 | bit              |
+-----------+----------------+--------+-------------+----------------+------------------+

The result is not null when a constant is specified without the function:

EXEC sp_describe_first_result_set N'SELECT 1 AS result;';

+-----------+----------------+--------+-------------+----------------+------------------+
| is_hidden | column_ordinal |  name  | is_nullable | system_type_id | system_type_name |
+-----------+----------------+--------+-------------+----------------+------------------+
|         0 |              1 | result |           0 |             56 | int              |
+-----------+----------------+--------+-------------+----------------+------------------+

But the result data type is int instead of the desired bit as SQL Server has no bit constant without implicit or explict conversion, ISNULL is needed to coerce a not null result as @MichaelGreen answered.