2016-05-31 17 views
6

実行中のMS SQL Server 2014 express。突然、ビュー内の列のうちの1つが、ヌル可能ではない2つの列の結合であるにもかかわらず、ヌル可能になりました。私はここで何が起こっているかを理解する助けてください:null不可能な列のUNIONはNULL可能です

enter image description here

とUNION:

enter image description here

私は何をしないのですか?

詳細情報を編集: IncomingTransactionsビューを再保存すると、その列はnullになりますが、そうではありません。数量列の定義は次のとおりです。(ケースPIN.StatusId時6 PIN .QuantityReceived 7 THEN 0 ELSE PIN.QuantityRevised END)AS数量。数量フィールドのそれぞれはnullではなく、caseステートメントは網羅的です。残りのクエリは、StatusIdフィールドの単純な結合です。これはnull以外のFKであるため、ここではまだ失われています。

編集2:以下YBの提案に基づいて、私はこの動作を再現する最小限のテストケースを作成しました:

Create Table ybTest1 (Q1 decimal (7,2) not null, X int not null); 
GO 
Create View ybTestNSB As 
Select (CASE X WHEN 0 THEN Q1 ELSE CAST(0 as decimal(7,2)) END) AS Q From ybTest1 
GO 

ybTest1ビューのQ列は、case文が網羅されていても、nullです。私がELSEブランチの0をでラップしても、YBが示唆しているように、それはまだnullです。 CASEには私が考えたセマンティクスがないか、これはバグです。

+1

奇妙な部分はステータスが 'not null'です。これはおそらくデータ型に依存します。どのようにビューを作成しましたか? 2つのテストテーブルを使って、すべてのデータ型がヌルで、ヌルでないことを推薦します。この動作を再現できるかどうかを確認してください。 –

+1

どのようにビューを使用していますか? WHERE句?集計?クエリによっては、2つ目のテーブルに存在しないレコードが1つのテーブルに存在する可能性があり、結果としてnullが使用される可能性があります。 UNIONは、重複を排除するためにソートとマージを行います。すべてのレコードが必要な場合は、UNION ALLを実行します。重複を気にしない場合、UNION ALLははるかに高速です。 – JVC

+0

@JuanCarlosOropeza、私はタイプ、ID、PartTypeIdとステータスを推測しているすべてのキーフィールドですか? Quantity、FiscalYearId、DateTransactedおよびSourceはそうではありません。 – Clay

答えて

2

式の結果として計算される各列は、SQL ServerではNULL可能と見なされます。この問題を回避するには、実行しているときにISNULLを使用します。これは、データベースエンジンが自動的に使用される式に基づいて 計算列のNULL値を許可するかどうかを判断し、ここでcomputed columns section

に記載されています。最も 式の結果が一定にヌル結果を置換非NULL値である場合にのみnonnullable列 は、NULL可能である発現はISNULL(check_expression, constant)を指定することにより、 nonnullable一つに変えることができる...存在していてもNULL可能であると考えられます。

ですが、ビュー定義を含む計算の結果として列が派生する場所であればどこでも適用されます。

ヌルが実際に可能かどうかを分析するロジックはほとんどありません(さまざまな推奨されないセットオプションがオーバーフローエラーではなくヌルを誘発する可能性があるため、1 + Xでもあなたの例ではnullが生成される可能性があります)慎重の側であなたのcase式が現実にはnullという出力を出すことはできませんが、私の経験ではほとんどすべての計算カラムはisnullで囲まれたものを除いてnullableとして扱われます。

だからあなたのテストケースであなたが迷惑な完全冗長表現を置くことを避けるために

Create View ybTestNSB As 
Select ISNULL(CASE X WHEN 0 THEN Q1 END, 0) AS Q From ybTest1 

Create View ybTestNSB As 
Select (CASE X WHEN 0 THEN Q1 ELSE CAST(0 as decimal(7,2)) END) AS Q From ybTest1 

を置き換えることができます。

+0

これはMartinの場合のようですが、それは[そのように文書化されていません](https://msdn.microsoft.com/en-us/library/ms181765.aspx?f=255&MSPPError=-2147217396)。引用:「input_expression = when_expressionがTRUEと評価されない場合、ELSE句が指定されている場合はSQL Serverデータベースエンジンはelse_result_expressionを返し、ELSE句が指定されていない場合はNULL値を返します。これは、単純で検索されたcase文でも同じです。私の例では、ELSE節は明らかにnullではありません。 – naasking

+0

@naskingはい、実際には、 'case'式はnullを返すことができません。しかし、これを分析するロジックはほとんどまたはまったくありません。ほとんどの計算カラムは、isnullでラップされたものを除いて、nullableとして扱われます。 –

+1

OK、2008 R2ではNULLを推測していませんでしたが、2014年にそれをやっています。私たちはこれを今すぐダブルチェックしました。したがって、MSSQL 2014は2008年よりも正確ではないようです。 – naasking

関連する問題