Sql-Server

為什麼 NOT NULL 計算列在視圖中被認為可以為空?

  • September 5, 2015

我有一張桌子:

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

我在 C# (LinqToSQL) 中有一個帶有FilteredRealty視圖的 dbml 模型。這*$$ Ranking $$*欄位被辨識為可為空的 int,因此每次更改數據庫中的任何內容時,我都必須修復生成程式碼中的類型。這對我來說非常令人沮喪,而且需要大量的手工工作。

FilteredRealty中沒有使用聚合(關於這個相關問題)。

如果Realty.Ranking不可為空,為什麼視圖的Ranking列被視為可空?

[Ranking]由於是計算列,該欄位顯示為“可空”。是的,它被聲明為NOT NULL,但正如 MSDN page for Computed Columns所述,數據庫引擎可以在查詢時更改該確定:

數據庫引擎根據使用的表達式自動確定計算列的可空性。即使只有不可為空的列存在,大多數表達式的結果也被認為是可空的,因為可能的下溢或溢出也會產生空結果。使用具有AllowsNull屬性的 COLUMNPROPERTY 函式來調查表中任何計算列的可空性。可以通過指定 ISNULL( check_expression , constant )將可空表達式轉換為不可空表達式,其中常量是替換任何空結果的非空值。

那麼,讓我們看看這是否屬實:

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

到目前為止,這看起來是積極的,但即使是最初的定義也從這兩項檢查中報告了“NOT NULL”。因此,讓我們嘗試真正的測試——數據庫引擎如何在執行時確定可空性:

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

引用自:https://dba.stackexchange.com/questions/114260