Tom*_*bes 17 null sql-server view computed-column
我有一张桌子:
CREATE TABLE [dbo].[Realty](
[Id] [int] IDENTITY(1,1) NOT NULL,
[RankingBonus] [int] NOT NULL,
[Ranking] AS ([Id]+[RankingBonus]) PERSISTED NOT NULL
....
)
Run Code Online (Sandbox Code Playgroud)
还有一个观点:
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
Run Code Online (Sandbox Code Playgroud)
我在 C# (LinqToSQL) 中有一个 dbml 模型,其中包含FilteredRealty视图。的[排名]字段被识别为可空int和所以我必须每次固定的类型在所生成的代码,当我更改数据库中的任何东西。这对我和大量手工工作来说非常令人沮丧。
FilteredRealty中没有使用聚合(关于这个相关问题)。
如果Realty.Ranking不可为空,为什么视图的Ranking列被视为可以为空?
Sol*_*zky 23
[Ranking]由于是计算列,该字段显示为“可空”。是的,它被声明为NOT NULL,但正如计算列的 MSDN 页面所述,数据库引擎可以在查询时更改该确定:
数据库引擎根据使用的表达式自动确定计算列的可为空性。即使只存在不可为空的列,大多数表达式的结果也被认为是可空的,因为可能的下溢或溢出也会产生空结果。使用带有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 == :-(
Run Code Online (Sandbox Code Playgroud)
现在让我们看看他们的建议是否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
Run Code Online (Sandbox Code Playgroud)
他们的建议看起来确实很准确,所以让我们尝试将其应用于计算列的定义:
ALTER TABLE dbo.Realty
ADD [RankingFixed] AS (ISNULL(([Id]+[RankingBonus]), -99))
PERSISTED NOT NULL;
GO
Run Code Online (Sandbox Code Playgroud)
现在我们再次检查属性,但对于新字段:
EXEC sp_help 'dbo.Realty';
-- RankingFixed: Nullable = "no"
SELECT COLUMNPROPERTY(OBJECT_ID(N'dbo.Realty'),
N'RankingFixed',
'AllowsNull') AS [AllowsNullsNow?];
-- 0
Run Code Online (Sandbox Code Playgroud)
到目前为止,这看起来是积极的,但即使是原始定义也从这两个检查中报告了“NOT NULL”。那么让我们尝试真正的测试——数据库引擎如何在运行时确定可空性:
SELECT * FROM sys.dm_exec_describe_first_result_set(N'SELECT * FROM dbo.Realty', '', NULL);
-- RankingFixed: is_nullable = 0 == :-) WOO HOO!
Run Code Online (Sandbox Code Playgroud)
Pau*_*ite 13
为保证Ranking计算列表达式在任何情况下都不会返回 NULL,您必须ISNULL使用合适的默认值将其包装起来。例如:
Ranking AS ISNULL(Id + RankingBonus, 0) PERSISTED NOT NULL
Run Code Online (Sandbox Code Playgroud)
NOT 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
Run Code Online (Sandbox Code Playgroud)
请注意使用,sys.sp_refreshsqlmodule因为您的视图不是模式绑定的。
| 归档时间: |
|
| 查看次数: |
8741 次 |
| 最近记录: |