为什么 sys.columns.is_nullable 可以为空?

Enr*_*eta 5 sql-server system-tables

我正在编写一个将映射到 C# 类的查询,并且在获取查询列的类型时,导致sys.columns中的某些列可以为 NULL

  • is_nullable
  • is_replicated
  • is_merge_published
  • is_dts_replicated

在同一个 sys.columns 中,还有其他非空的

  • is_rowguidcol
  • is_identity
  • is_computed

注意:这些列有点

我认为它们应该总是 NOT NULL,因为 SQL Server 必须知道列的属性。

那么,为什么有些/那些列sys.columns可以NULL和/或在哪些情况下它们会是?

Aar*_*and 5

你是对的,结果永远不可能NULL。从快速调查中,看看sys.columns. 如果我运行:

SELECT OBJECT_DEFINITION(OBJECT_ID(N'sys.columns'));
Run Code Online (Sandbox Code Playgroud)

我看到这个:

...
sysconv(bit, 1 - (c.status & 1)) AS is_nullable,        -- CPM_NOTNULL
...
FROM sys.syscolpars c
...
Run Code Online (Sandbox Code Playgroud)

如果我更改为 DAC 连接,则可以查看此处的列:

SELECT name, is_nullable
  FROM sys.all_columns
  WHERE [object_id] = OBJECT_ID(N'sys.syscolpars')
  AND name = N'status';
Run Code Online (Sandbox Code Playgroud)

结果:

name    is_nullable
------  -----------
status  0
Run Code Online (Sandbox Code Playgroud)

所以源绝对不能为空,对吗?但是,如果您对 执行相同操作sys.columns,则涉及周围表达式的列将c.status被标记为is_nullable = 1。这更多地反映了所涉及的表达式/数据类型,而不是NULL值的实际可能性。

我最初认为可能SYSCONV()做了一些与CONVERT()(我们不能使用前者来检查,但我认为它可能在内部工作更像TRY_CONVERT())不同的东西。事实并非如此,事实上,即使没有任何内部知识,也很容易重现:

CREATE TABLE dbo.foo(bit_column bit NOT NULL);
GO

CREATE VIEW dbo.bar 
AS                                                      -- nullable?
  SELECT bit_col1 = CONVERT(bit, 1 - (bit_column & 1)), -- YES
         bit_col2 = bit_column & 1, -- no convert       -- NO
         bit_col3 = 1 - bit_column & 1                  -- YES
  FROM dbo.foo;
GO

SELECT name, is_nullable
  FROM sys.dm_exec_describe_first_result_set
       (N'SELECT * FROM dbo.bar', NULL, 1);
GO

DROP TABLE dbo.foo;
DROP VIEW dbo.bar;
Run Code Online (Sandbox Code Playgroud)

结果:

name      is_nullable
--------  -----------
bit_col1  1
bit_col2  0
bit_col3  1
Run Code Online (Sandbox Code Playgroud)

说了这么多,不知道该给你什么建议。你可以有条件地硬编码这个特定的列是不可为空的,不管元数据是什么,或者你可以安全地使用它并使用元数据告诉你的东西(这将在未来基础定义发生变化的情况下证明你版本)。