web-dev-qa-db-ja.com

ビューの選択クエリで完全に確定的ですべてを網羅する「ケース」の結果がnull可能であるのはなぜですか?

Idを主キーとするテーブルがあります。

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

このテーブルをObject Explorerで見ると、もちろん次の画像が表示されます。

Enter image description here

ご覧のとおり、列Idnot nullです。

次に、このダミーテーブルにダミービューを作成します。

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

しかし今回は、オブジェクトエクスプローラーに次の結果が表示されます。

Enter image description here

ご覧のとおり、私のcase句はすべてを網羅しており、すべてのレコードの100%をカバーしていて、すべてのレコードに対する回答があるにもかかわらず、null可能です。

SQL Serverにこの奇妙な動作があるのはなぜですか?そして、どうすればそれを強制的にnullにしないのですか?

PS動的にコードを生成するインフラストラクチャがあり、この動作により問題が発生し、手動ですべてのbool?タイプを変更する必要がありますC#からboolに。

3
Saeed Neamati

質問の理由の部分に答えるために、CASE関数の結果はnull可能であるため、CAST式の結果はnull可能です。これは次のようにして観察できます:

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

結果(省略):

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

関数なしで定数が指定されている場合、結果はnullではありません。

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              |
+-----------+----------------+--------+-------------+----------------+------------------+

ただし、SQL Serverには暗黙的または明示的な変換なしにint定数がないため、結果のデータ型はbitではなくbitです。強制するにはISNULLが必要です@MichaelGreenが答えたnullではない結果。

8
Dan Guzman

あなたの実際の質問に答えるために-私にはわからない。私の推測では、パーサーは列を直接検査してヌル可能性を判別できると思います。列参照と出力の間に関数や式などのnull可能性に影響を与える可能性のあるものがあれば、出力はnull可能と見なされます。 MSは、すべての状況を詳細に調査し、結果について理由を説明するコードを作成していません。彼らも、他の皆と同じように、予算とタイムラインとバックログを持っています。これは単に優先されていません。

しかし、その仮説は私に考えさせられました。それが列を解釈できる場合、どのような構造が考えられますか? nullでないことが保証されている十分に単純な式を提供できれば、目的の出力が生成されます。答えはイエスです [〜#〜] isnull [〜#〜]

create or alter view IdIsTwoView
as

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

置換値には-1を選択しました。これはIDの範囲外であるため、見れば明らかなエラーになります。どんな定数でも機能すると思います。

6
Michael Green