如果要确定NVARCHAR / NCHAR / NTEXT 列中是否有任何字符无法转换为VARCHAR,则需要使用_BIN2 变体转换为VARCHAR用于该特定列的排序规则。例如,如果特定列使用Albanian_100_CI_AS,那么您将指定Albanian_100_BIN2 进行测试。使用_BIN2 排序规则的原因是非二进制排序规则只会找到代码页中至少有一个字符根本没有任何映射并因此转换为? 的实例。但是,非二进制排序规则不会捕获没有直接映射到代码页中的字符的实例,而是具有“最适合”映射的字符。例如,上标 2 字符 ² 在代码页 1252 中有直接映射,因此绝对没有问题。另一方面,它在代码页 1250(由阿尔巴尼亚排序规则使用)中没有直接映射,但它确实有一个“最合适”的映射,可以将其转换为常规的 2。非二进制排序规则的问题在于2 将等同于²,因此它不会注册为无法转换为VARCHAR 的行。例如:
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE French_100_CI_AS); -- Code Page 1252
-- ²
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS); -- Code Page 1250
-- 2
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS)
WHERE N'²' <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS));
-- (no rows returned)
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2)
WHERE N'²' <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2));
-- 2
理想情况下,您应该显式转换回NVARCHAR,以便代码清楚地知道它在做什么,尽管不这样做仍然会隐式转换回NVARCHAR,因此无论哪种方式行为都是相同的。
请注意只使用MAX 类型。不要使用NVARCHAR(4000) 或VARCHAR(4000) 否则您可能会因为NVARCHAR(MAX) 列中的数据被截断而得到误报。
因此,就问题中的示例代码而言,查询将是(假设正在使用 Latin1_General 排序规则):
SELECT usr.*
FROM dbo.[users] usr
WHERE usr.[name] <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), usr.[name] COLLATE Latin1_General_100_BIN2))
OR usr.[address] <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), usr.[address] COLLATE Latin1_General_100_BIN2))
OR usr.[description] <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), usr.[description] COLLATE Latin1_General_100_BIN2));