patternsqlMinor
Why sys.columns.is_nullable can be null?
Viewed 0 times
whycancolumnsnullis_nullablesys
Problem
I'm writing a query that will be mapped to a C# class, and when getting the type of the query's columns, it results that some columns in sys.columns can be NULL
And in the same sys.columns there are others that are NOT NULL
NOTE: Those columns are bit
I think they should always be NOT NULL, because SQL Server must know the columns' properties.
So, why some/those columns in
- is_nullable
- is_replicated
- is_merge_published
- is_dts_replicated
And in the same sys.columns there are others that are NOT NULL
- is_rowguidcol
- is_identity
- is_computed
NOTE: Those columns are bit
I think they should always be NOT NULL, because SQL Server must know the columns' properties.
So, why some/those columns in
sys.columns can be NULL and/or in which cases they will be?Solution
You are right that it is not possible for the outcome to ever be
I see this:
If I change to a DAC connection, I can look at the columns here:
Results:
So the source is definitely not nullable, right? Yet if you do the same for
I initially thought maybe
Results:
All that said, I don't know what advice to give you. You could conditionally hard-code that this specific column is not nullable in spite of what the metadata says, or you could play it safe and use what the metadata tells you (which will future-proof you in the event the underlying definitions change in future versions).
NULL. From quick investigation, take a look at the definition of sys.columns. If I run:SELECT OBJECT_DEFINITION(OBJECT_ID(N'sys.columns'));I see this:
...
sysconv(bit, 1 - (c.status & 1)) AS is_nullable, -- CPM_NOTNULL
...
FROM sys.syscolpars c
...If I change to a DAC connection, I can look at the columns here:
SELECT name, is_nullable
FROM sys.all_columns
WHERE [object_id] = OBJECT_ID(N'sys.syscolpars')
AND name = N'status';Results:
name is_nullable
------ -----------
status 0So the source is definitely not nullable, right? Yet if you do the same for
sys.columns, columns involving expressions around c.status are marked as is_nullable = 1. That's more a reflection of the expressions / data types involved than the actual possibility of a NULL value.I initially thought maybe
SYSCONV() did something differently from CONVERT() (we can't use the former to check, but I thought maybe it might internally work more like TRY_CONVERT()). This is not the case, in fact this is quite easy to reproduce even without any internals knowledge: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;Results:
name is_nullable
-------- -----------
bit_col1 1
bit_col2 0
bit_col3 1All that said, I don't know what advice to give you. You could conditionally hard-code that this specific column is not nullable in spite of what the metadata says, or you could play it safe and use what the metadata tells you (which will future-proof you in the event the underlying definitions change in future versions).
Code Snippets
SELECT OBJECT_DEFINITION(OBJECT_ID(N'sys.columns'));...
sysconv(bit, 1 - (c.status & 1)) AS is_nullable, -- CPM_NOTNULL
...
FROM sys.syscolpars c
...SELECT name, is_nullable
FROM sys.all_columns
WHERE [object_id] = OBJECT_ID(N'sys.syscolpars')
AND name = N'status';name is_nullable
------ -----------
status 0CREATE 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;Context
StackExchange Database Administrators Q#218979, answer score: 5
Revisions (0)
No revisions yet.