Sql-Server
為什麼 NOT NULL 計算列在視圖中被認為可以為空?
我有一張桌子:
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!