通过


将 Unicode 列类型转换为二进制排序规则的 SQL Server 查询返回不正确的结果

本文可帮助你解决当语句包含为 Unicode 列定义的或INOR子句并包含collate将 Unicode 列类型转换为另一个二进制排序规则时发生的问题。

原始产品版本:SQL Server
原始 KB 数: 3053639

现象

SQL Server 数据库中有一个表,其中满足以下条件:

  • 该表包含 Unicode 列。 例如,表有一列 nchar(5)
  • Unicode 列的排序规则为 Latin1_General_BIN.
  • 同一 Unicode 列是索引的一部分。 但是,针对此表运行的 T-SQL 语句可能会返回不正确的结果。 如果满足以下条件,则会出现此问题:
    • T-SQL 语句包含为同一 Unicode 列定义的或INOR子句。
    • T-SQL 语句包含 collate 将 Unicode 列类型化为另一个二进制排序规则。

示例查询:

CREATE TABLE [dbo].[Table_1]([Col1] [smallint] NOT NULL,
[Col2] [nchar](5),
[Col3] [nchar](5) COLLATE Latin1_General_BIN NOT NULL, -- Col3 , a Unicode Column with "Latin1_General_BIN" collation
CONSTRAINT [PK__Table_1] PRIMARY KEY CLUSTERED -- Primary Key on all the 3 columns
([Col1] ASC,
[Col2] ASC,
[Col3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SELECT * FROM Table_1 WHERE Col1 = 1 AND Col2 = '1' AND Col3 COLLATE Chinese_PRC_BIN IN (N'1' ,N'2')  -- This statement using "IN" and "collate" might give incorrect results.
GO

SELECT * FROM Table_1 WHERE Col1 = 1 AND Col2 = '1' AND (Col3 COLLATE Chinese_PRC_BIN = N'1' OR Col3 COLLATE Chinese_PRC_BIN = N'2') -- This statement using "OR" and "collate" might give incorrect results.
GO

解决方法

若要解决此问题,请确保 Unicode 列(“症状”部分中的示例查询中的 Col3)满足以下条件之一:

  • char(5)数据类型或 nvarchar(5).
  • 通过使用所需排序规则的 Chinese_PROC_BIN 相同排序规则来定义(请注意 Chinese_PROC_BIN 这只是一个示例;其他二进制排序规则也适用)。
  • 不是排序规则 Latin1_General_BIN
  • 按 CI 排序规则进行排序。 例如:collate Chinese_PRC_90_CI_AI IN (N'1 ', N'2 ')
  • 与与列长度匹配的常量进行比较。 例如,collate Chinese_PRC_BIN IN (N'1 ', N'2 ')
  • 不是索引的一部分,或者表扫描是使用表提示强制进行的 FORCESCAN
  • 例如 RTRIMLTRIM 用于强制表扫描的函数。

详细信息

若要重现此问题,请运行以下脚本:

CREATE DATABASE Test_DB
GO

USE Test_DB
GO

CREATE TABLE [dbo].[Table_1]([Col1] [smallint] NOT NULL,
[Col2] [nchar](5),
[Col3] [nchar](5) COLLATE Latin1_General_BIN NOT NULL, -- Col3 , a Unicode Column with "Latin1_General_BIN" collation

CONSTRAINT [PK__Table_1] PRIMARY KEY CLUSTERED -- Primary Key on all the 3 columns
([Col1] ASC,
[Col2] ASC,
[Col3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

-- Populate the table with a sample script as below

DECLARE @x AS INT
DECLARE @y AS INT

SET @x=1
SET @y=1

WHILE (@x<=2)
BEGIN
WHILE (@y<=1000)
BEGIN
INSERT INTO Table_1 values (@x,@y,@y)
SET @y=@y+1
END
SET @x=@x +1
END
GO

SELECT * FROM Table_1 WHERE Col1 = 1 AND Col2 = '1' AND Col3 COLLATE Chinese_PRC_BIN = N'1' -- Expected output of one row.
GO

SELECT * FROM Table_1 WHERE Col1 = 1 AND Col2 = '1' AND Col3 COLLATE Chinese_PRC_BIN IN (N'1' ,N'2') -- No rows returned when output for Col3= N'1' is expected.
GO

SELECT * FROM Table_1 WHERE Col1 = 1 AND Col2 = '1' AND (Col3 COLLATE Chinese_PRC_BIN = N'1' OR Col3 COLLATE Chinese_PRC_BIN = N'2') -- No rows returned when output for Col3= N'1' is expected.
GO

适用于

  • SQL Server 2014 Business Intelligence
  • SQL Server 2014 开发人员
  • SQL Server 2014 Enterprise
  • SQL Server 2014 Enterprise Core
  • SQL Server 2014 Express
  • SQL Server 2014 Standard
  • SQL Server 2014 Web
  • SQL Server 2012 商业智能
  • SQL Server 2012 开发人员
  • SQL Server 2012 企业版
  • SQL Server 2012 Express
  • SQL Server 2012 Standard
  • SQL Server 2012 Web
  • SQL Server 2012 Enterprise Core
  • SQL Server 2008 R2 Datacenter
  • SQL Server 2008 R2 Developer
  • SQL Server 2008 R2 Enterprise
  • SQL Server 2008 R2 Express
  • SQL Server 2008 R2 并行数据仓库
  • SQL Server 2008 R2 Standard
  • SQL Server 2008 R2 Web
  • SQL Server 2008 R2 Workgroup
  • SQL Server 2008 Developer
  • SQL Server 2008 Enterprise
  • SQL Server 2008 Express
  • SQL Server 2008 Standard
  • SQL Server 2008 Web
  • SQL Server 2008 Workgroup
  • SQL Server 2005 Developer Edition
  • SQL Server 2005 Enterprise Edition
  • SQL Server 2005 Express Edition
  • SQL Server 2005 Standard Edition
  • SQL Server 2005 Standard X64 Edition
  • SQL Server 2005 Workgroup Edition