27

这是查询:

  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 个其他字段,当字段不为空且 LEN(字段) 为空时,两个 varchar(max) 都返回行。所有这些字段都曾经是 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
4

5 回答 5

19

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

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

更新:它似乎与TEXT列中的大值没有任何关系。短值显示相同的行为(扩展示例)。因此,重要的是NULL通过UPDATE和转换的显式设置。

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

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

于 2012-04-27T09:26:17.193 回答
6

这只是McSim使用 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不管(其值自初始插入以来从未更新)中获取值。

于 2012-04-28T11:42:39.840 回答
1

科林:

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

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

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

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

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

此致

于 2012-04-26T16:51:43.693 回答
0

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

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

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

于 2012-04-26T13:32:16.300 回答
0

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

于 2014-05-26T01:47:56.567 回答