【问题标题】:Why is IS NOT NULL returning NULL values for a Varchar(max) in SQL Server?为什么 IS NOT NULL 在 SQL Server 中为 Varchar(max) 返回 NULL 值?
【发布时间】:2012-05-04 23:07:20
【问题描述】:

  1. 列表中似乎出现了一些 NULL 值。
  2. 某些 NULL 值正在被查询过滤掉。我已经检查过了。
  3. 如果我添加AND AdditionalFields = '',仍然返回这两个结果
  4. AdditionalFields 是一个 varchar(max)
  5. 数据库是 SQL Server 10,兼容级别 = Sql Server 2005 (90)
  6. 我正在使用 Management Studio 2008

我似乎有长度为 NULL 的空字符串,或等于空字符串的 NULL 值。这是一种新的数据类型吗?!

编辑: 新数据类型 - 在此称为“Numpty”

编辑 2 将数据插入临时表会将 Numpties 变为 NULLS。 (这条sql的结果是10)

CREATE TABLE #temp(ID uniqueidentifier , Value varchar(max))

INSERT INTO #temp 
SELECT top 10 g.ID, g.AdditionalFields
FROM grants g 
WHERE g.AdditionalFields IS NOT NULL AND LEN(g.AdditionalFields) IS NULL

SELECT COUNT(*) FROM #temp WHERE Value is null

DROP TABLE #temp

编辑 3 我可以通过运行更新来修复数据:

UPDATE Grants SET AdditionalFields = NULL
WHERE AdditionalFields IS NOT NULL AND LEN(AdditionalFields) IS NULL

所以这让我认为字段必须包含一些东西,而不是架构定义的一些问题。但它是什么?以及如何阻止它再次出现?

编辑 4 我的数据库中还有 2 个其他字段,两个 varchar(max) 在字段不为空且 LEN(field) 为空时返回行。所有这些字段都曾经是 TEXT 并更改为 VARCHAR(MAX)。数据库也从 Sql Server 2005 移动到 2008。看起来我们默认关闭了 ANSI_PADDING 等。

另一个例子:

转换为 varbinary

执行计划: 编辑 5: 删除了表定义 - 最终证明是不相关的

编辑 6 生成脚本以将 TEXT 更改为 VARCHAR(MAX) 然后更新值以防止错误并提高性能

--Generate scripts to alter TEXT to VARCHAR(MAX)
SELECT 'ALTER TABLE [' + tab.table_schema + '].[' + tab.table_name  + '] ALTER COLUMN [' + col.column_name + '] VARCHAR(MAX)' + CASE WHEN col.IS_NULLABLE = 'YES' THEN ' NULL' ELSE ' NOT NULL' END + ' GO'
FROM INFORMATION_SCHEMA.tables tab
INNER JOIN INFORMATION_SCHEMA.COLUMNS col ON col.table_name = tab.table_name
          AND tab.table_schema = col.table_schema
          AND tab.table_catalog = col.table_catalog
WHERE tab.table_type <> 'VIEW' and col.DATA_TYPE = 'text'

--Generate scripts to set value to value in VARCHAR(MAX) fields
SELECT 'UPDATE [' + tab.table_schema + '].[' + tab.table_name  + '] SET [' + col.column_name + '] = [' + col.column_name + ']'
FROM INFORMATION_SCHEMA.tables tab
INNER JOIN INFORMATION_SCHEMA.COLUMNS col ON col.table_name = tab.table_name
          AND tab.table_schema = col.table_schema
          AND tab.table_catalog = col.table_catalog
WHERE tab.table_type <> 'VIEW' AND col.DATA_TYPE = 'varchar' and col.CHARACTER_MAXIMUM_LENGTH = -1

【问题讨论】:

  • 您的查询是逐字发布的吗?您是否有可能在WHERE 子句中拼错了AdditionalFields,但在SELECT 列表中却没有(这会导致在另一个字段上进行过滤)?像WHERE 'g.AdditionalFields' IS NOT NULL 这样的东西会产生类似的行为(因为你过滤的不是字段而是字符串常量)。
  • 第一个结果并不令人惊讶。空字符串和NULL 是两个独立的概念(除非你很奇怪,比如 Oracle)
  • 作为调试提示:只需输出 PK,以便您看到生成结果的行。
  • 当我们这样做时,您可以发布整个 ssms 窗口的屏幕截图,以便我们更轻松地验证您的声明。
  • I've created a connect item for this。我还没有测试过这个问题是否发生在 SQL Server 2012 中。

标签: sql-server sql-server-2005


【解决方案1】:

我得到了一个示例代码来重现上述行为。当您有一个 TEXT 字段存储的值大于它可以容纳在一行中时,如果您之后将其设置为 NULL 并将列转换为 VARCHAR(MAX),则会出现问题。

较大的值存储在单独的页面中。然后将此字段的值设置为NULL。如果您现在将此列转换为VARCHAR(MAX),则 SQL Server 似乎无法正确处理。通常在 TEXTVARCHAR(MAX) 的转换中,外部页面保持原样,但可能是因为它被设置为 NULL,所以更改的列会搞砸。

更新:这似乎与TEXT 列中的大值无关。短值显示相同的行为(扩展示例)。所以这只是通过UPDATENULL 的显式设置以及重要的转换。

CREATE TABLE [dbo].[Test](
    [Id] [int] NOT NULL,
    [Value] [text] NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

INSERT INTO Test VALUES (1, 'test')
INSERT INTO Test VALUES (2, '')
INSERT INTO Test VALUES (3, NULL)
INSERT INTO Test VALUES (4, '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789')
INSERT INTO Test VALUES (5, 'short string')
GO

update test SET value = null where ID = 4
update test SET value = null where ID = 5
GO

ALTER TABLE test ALTER COLUMN value varchar(max)
GO

select id, value, len(value) as length
from test
where value is not null
GO

结果是:

1   test    4
2           0
4   NULL    NULL
5   NULL    NULL

解决此问题的一个简单方法是重新分配 VARCHAR(MAX) 列中的值。

UPDATE Test SET value = value

这似乎将值放在先前存储在外部页面中的行中。 (参考:NTEXT vs NVARCHAR(MAX) in SQL 2005

【讨论】:

  • 文本数据类型是这里的问题;您需要在 datalength(Value)=0 的情况下以不同的方式处理它们。更多详情请见stackoverflow.com/questions/33409/…
  • @u07ch:仔细阅读问题。这不是关于 TEXT 数据类型,而是关于 VARCHAR(MAX) NULL 值在使用 IS NOT NULL 检查时给出 TRUE。
  • +1 用于提供回购。显式插入NULL 的行是该列中唯一将NULL_BITMAP 设置为1 的行。对于text 数据类型,我之前注意到更新到NULL 不会更新位图,但似乎在指针的其他地方设置了某种标志或指向结构。如果您在转换为max 之前执行select [Id], [Value] from [Test] where [Value] is not null,则返回正确的结果,但NULL_BITMAP 仍然显示为零,因此它必须查看其他地方才能确定。
  • 伟大的 MicSim 故障排除:您将问题简化为一组特定的步骤,重现不需要的行为,并找到解释,恭喜!
  • 太棒了!谢谢。最好去修复我们数据库中的所有 Text 和 Varchar(max) 字段...
【解决方案2】:

这只是对McSim's answer 的补充,使用 SQL Server Internals Viewer 查看各个阶段。

CREATE TABLE [dbo].[Test](
    [Id] [int] NOT NULL PRIMARY KEY ,
    [Value] [text] NULL)


INSERT INTO Test VALUES (1, '')

初始插入后的行

初始插入后的文本值

update [Test] SET [Value] = null 

更新为NULL后的行

这与前面显示的行相同,因此我没有重复屏幕截图。具体来说,NULL_BITMAP 确实不会更新以反映新的 NULL 值。

更新为NULL后的文本值

Type 位已更改,Internals Viewer 将其显示为不再包含 Data 列的值。

此时正确运行以下命令不会返回任何行

SET STATISTICS IO ON
select [Id]
from [Test]
where [Value] is not null

因此 SQL Server 必须跟随文本指针并查看那里的值以确定 NULL 能力。

ALTER TABLE [Test] ALTER COLUMN [Value] varchar(max)

这只是元数据更改。行内数据和行外数据均保持不变。

但是此时运行以下错误会返回该行。

SET STATISTICS IO ON
select [Id]
from [Test]
where [Value] is not null

STATISTICS IO的输出

扫描计数 1,逻辑读取 2,... lob 逻辑读取 1

表明它实际上仍然遵循文本指针,但大概在varchar(max) 的情况下,必须有一个不同的代码路径错误地最终从NULL_BITMAP 中获取值,无论如何(其值从未更新自最初插入以来)。

【讨论】:

  • 非常感谢马丁。如果我有权在服务器上执行此操作,我们会更快到达这里。我们复制了一份备份,但我昨天没有时间尝试。
【解决方案3】:

科林:

我很确定这一切都是因为数据库转换而发生的。既然你需要尽快解决这件事,我的建议是先保证你的 AdditionalFields 数据没问题,然后试着理解为什么会这样:

  1. 进行备份;
  2. 运行这个 T-SQL:

    update grants
    set AdditionalFields = ltrim(rtrim(isnull(AdditionalFields,'')))
    

isnull 函数会将你的 null 值转换为空字符串,左/右修剪应该保证即使有多个空格的字段之后也会有相同的值。

您能否运行此程序并稍后将结果反馈给我们?

最好的问候

【讨论】:

  • 我已经知道我可以通过运行更新将 numpties 变为空值(我在事务中运行了上面的更新)所以我不确定这会告诉我们更多信息。我想保留数据以帮助进行调查,并且该问题尚未导致任何重大问题。我没有足够的权限查看底层页面数据,所以我想我会尝试备份数据库文件并将其拉到我拥有管理员权限的系统上。现在不上班,明天继续收听……
【解决方案4】:

正如其他人指出的那样,这个结果是完全不可能的。

  1. 请发一张实际执行计划的截图。
  2. 请运行 dbcc checkdb 并发布错误消息(如果有)。

(2) 实际上是我现在最喜欢的。

【讨论】:

  • CHECKDB 在数据库中发现 0 个分配错误和 0 个一致性错误
【解决方案5】:

我怀疑 NULL 这个词需要存储在数据库中,使用 select * from blah where mycolumn = 'NULL'

【讨论】:

    猜你喜欢
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    • 1970-01-01
    相关资源
    最近更新 更多