ビューでNOT NULL計算列がNULL可能と見なされるのはなぜですか?


15

私はテーブルを持っています:

CREATE TABLE [dbo].[Realty](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [RankingBonus] [int] NOT NULL,
    [Ranking]  AS ([Id]+[RankingBonus]) PERSISTED NOT NULL
    ....
)

そしてビュー:

CREATE View  [dbo].[FilteredRealty] AS
 SELECT 
realty.Id as realtyId,
...
COALESCE(realty.Wgs84X, ruian_cobce.Wgs84X, ruian_obec.Wgs84X) as Wgs84X,
COALESCE(realty.Wgs84Y, ruian_cobce.Wgs84Y, ruian_obec.Wgs84Y) as Wgs84Y,
realty.Ranking,
...
FROM realty
JOIN Category ON realty.CategoryId = Category.Id
LEFT JOIN ruian_cobce ON realty.cobceId = ruian_cobce.cobce_kod
LEFT JOIN ruian_obec ON realty.obecId = ruian_obec.obec_kod
LEFT JOIN okres ON realty.okresId = okres.okres_kod
LEFT JOIN ExternFile ON realty.Id = ExternFile.ForeignId AND ExternFile.IsMain = 1
                     AND ExternFile.ForeignTable = 5
INNER JOIN Person ON realty.OwnerId = Person.Id
WHERE Person.ConfirmStatus = 1

FilteredRealtyビューを持つC#(LinqToSQL)のdbmlモデルがあります。[ランキング]フィールドがNULL可能intとして、私は、生成されたコードで、私は、データベースに何かを変更するたびに形を修正する必要がありますので認識されています。これは私と多くの手作業にとって非常にイライラさせられます。

FilteredRealtyで使用される集計はありません(この関連する質問に関して)。

Realty.RankingがNULL可能でない場合、ビューのランキング列がNULL可能と見なされるのはなぜですか?

回答:


18

[Ranking]フィールドが原因計算カラムであることに「NULL可能」と表示されています。はい、と宣言さNOT NULLれていますが、計算列の MSDNページにあるように、データベースエンジンはクエリ時にその決定を変更できます。

データベースエンジンは、使用される式に基づいて、計算列のNULL可能性を自動的に判断します。可能性のあるアンダーフローまたはオーバーフローによってnull結果も生成されるため、ほとんどの式の結果は、null不可列のみが存在する場合でもnull可能と見なされます。AllowsNullプロパティを指定したCOLUMNPROPERTY関数を使用して、テーブル内の計算列のNULL 可能性を調査します。NULL可能式は、ISNULL(check_expressionconstant)を指定することにより、NULL不可の式に変換できます。ここで、定数は、任意のNULL結果に置き換えられる非NULL値です。

それで、これが本当かどうか見てみましょう:

CREATE TABLE [dbo].[Realty](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [RankingBonus] [int] NOT NULL,
    [Ranking]  AS ([Id]+[RankingBonus]) PERSISTED NOT NULL
);
GO

EXEC sp_help 'dbo.Realty';
-- Ranking: Nullable = "no"

SELECT COLUMNPROPERTY(OBJECT_ID(N'dbo.Realty'), N'Ranking', 'AllowsNull') AS [AllowsNull?];
-- 0

SELECT * FROM sys.dm_exec_describe_first_result_set(N'SELECT * FROM dbo.Realty', '', NULL);
-- Ranking: is_nullable = 1  ==  :-(

では、ISNULL作品に関するアドバイスを見てみましょう。

SELECT * FROM sys.dm_exec_describe_first_result_set(
   N'SELECT Id, RankingBonus, ISNULL(Ranking, -99) AS [RealRanking] FROM dbo.Realty;',
   '',
   NULL);
-- RealRanking: is_nullable = 0

彼らのアドバイスは正確に思えるので、計算列の定義にそれを適用してみましょう。

ALTER TABLE dbo.Realty
  ADD [RankingFixed] AS (ISNULL(([Id]+[RankingBonus]), -99))
  PERSISTED NOT NULL;
GO

そして、プロパティを再度確認しますが、新しいフィールドについては:

EXEC sp_help 'dbo.Realty';
-- RankingFixed: Nullable = "no"

SELECT COLUMNPROPERTY(OBJECT_ID(N'dbo.Realty'),
                      N'RankingFixed',
                      'AllowsNull') AS [AllowsNullsNow?];
-- 0

これはこれまでのところポジティブに見えますが、元の定義でさえ、これら2つのチェックから「NOT NULL」を報告しました。それでは、実際のテストを試してみましょう-データベースエンジンが実行時にNULL可能性を判断する方法:

SELECT * FROM sys.dm_exec_describe_first_result_set(N'SELECT * FROM dbo.Realty', '', NULL);
-- RankingFixed: is_nullable = 0  ==  :-) WOO HOO!

13

ランキング計算列式がどのような状況でもNULLを返さないことを保証するにISNULLは、適切なデフォルト値でラップする必要があります。例えば:

Ranking AS ISNULL(Id + RankingBonus, 0) PERSISTED NOT NULL

NOT NULL制約は、テーブルが変更されたときに永続値が有効で卓上およびセッションレベルの設定のコンテキストでは、nullでない保証します。

ただし、クエリがその式を参照する場合、SQL Serverは永続化された値を使用するか(設定が一致する場合)、式を新たに計算するかを選択できます。

たとえば、一部のセッション設定では、オーバーフローがNULLを返す可能性があるため、SQL Serverはこの可能性を考慮する必要があります。ビューを介してアクセスすると、SQL Serverは、列にNULLを返す可能性があるとして正しくマークを付けます。

ISNULL式の一番外側を使用することが、目的を達成するための唯一のサポートされる方法です。COALESCEたとえば、使用は機能しません。

デモ:

CREATE TABLE dbo.T1
(
    c1 integer NOT NULL,
    c2 integer NOT NULL,
    c3 AS c1 + c2 PERSISTED NOT NULL
);
GO
CREATE VIEW dbo.V1
AS
SELECT T.c1,
       T.c2,
       T.c3
FROM dbo.T1 AS T;
GO
SELECT AllowsNull = COLUMNPROPERTY(OBJECT_ID(N'dbo.V1', N'V'), N'c3', 'AllowsNull');
GO
ALTER TABLE dbo.T1
DROP COLUMN c3;
GO
ALTER TABLE dbo.T1
ADD c3 AS ISNULL(c1 + c2, 0) PERSISTED NOT NULL;
GO
EXECUTE sys.sp_refreshsqlmodule
    @name = N'dbo.V1';
GO
SELECT AllowsNull = COLUMNPROPERTY(OBJECT_ID(N'dbo.V1', N'V'), N'c3', 'AllowsNull');
GO
DROP VIEW dbo.V1;
DROP TABLE dbo.T1;
GO

sys.sp_refreshsqlmoduleビューはスキーマにバインドされていないため、の使用に注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.