Id
を主キーとするテーブルがあります。
create table Anything
(
Id bigint not null primary key identity(1, 1)
)
このテーブルをObject Explorer
で見ると、もちろん次の画像が表示されます。
ご覧のとおり、列Id
はnot 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
しかし今回は、オブジェクトエクスプローラーに次の結果が表示されます。
ご覧のとおり、私のcase
句はすべてを網羅しており、すべてのレコードの100%をカバーしていて、すべてのレコードに対する回答があるにもかかわらず、null可能です。
SQL Serverにこの奇妙な動作があるのはなぜですか?そして、どうすればそれを強制的にnullにしないのですか?
PS動的にコードを生成するインフラストラクチャがあり、この動作により問題が発生し、手動ですべてのbool?
タイプを変更する必要がありますC#からbool
に。
質問の理由の部分に答えるために、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ではない結果。
あなたの実際の質問に答えるために-私にはわからない。私の推測では、パーサーは列を直接検査してヌル可能性を判別できると思います。列参照と出力の間に関数や式などの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の範囲外であるため、見れば明らかなエラーになります。どんな定数でも機能すると思います。