比较 sql_variant 与 varchar 文字时出现排序规则冲突

Luk*_*til 6 sql-server collation sql-variant-property

我发现下面的查询在运行相同兼容性级别、相同设置选项等的两个 Azure 超大规模数据库上返回不同的结果。

IF CAST(ServerProperty('Edition') AS nvarchar(128)) = 'SQL Azure' BEGIN
    SELECT 1
END
IF ServerProperty('Edition') = 'SQL Azure' BEGIN
    SELECT 2
END
IF 'SQL Azure' = ServerProperty('Edition') BEGIN
    SELECT 3
END
Run Code Online (Sandbox Code Playgroud)

在一个数据库上,它仅返回 1,在其他数据库上,它返回 1,2 和 3。

我调查了根本原因,似乎是由数据库的排序规则不同引起的。

对于以下查询:

SELECT SQL_VARIANT_PROPERTY(ServerProperty('Edition'), 'Collation')
SELECT name, collation_name, compatibility_level FROM sys.databases
Run Code Online (Sandbox Code Playgroud)

数据库只返回一行,结果是:

-----------------------------
SQL_Latin1_General_CP1_CI_AS

name         collation_name                   compatibility_level
------------ -------------------------------- -------------------
master       SQL_Latin1_General_CP1_CI_AS     140
my_database  SQL_Latin1_General_CP850_CI_AS   150
Run Code Online (Sandbox Code Playgroud)

数据库返回1,2,3的结果是:

-----------------------------
SQL_Latin1_General_CP1_CI_AS

name         collation_name                   compatibility_level
------------ -------------------------------- -------------------
master       SQL_Latin1_General_CP1_CI_AS     140
my_database  SQL_Latin1_General_CP1_CI_AS     150
Run Code Online (Sandbox Code Playgroud)

因此,不进行强制转换的简单比较是sql_variantvarchar(当我使用时没有区别N'SQL Azure')进行比较,其中底层的nvarchar排序sql_variant规则在一种情况下与我查询的数据库不同,而在其他情况下它是匹配的。

首先,我假设具有不同排序规则的两个字符串的比较会失败,就像尝试连接具有不同排序规则的两列时失败一样,但这里显然不是这种情况。

无论如何,安全比较函数输出的最佳方法是sql_variant什么varchar

Pau*_*ite 7

该类型位于数据优先级层次结构的顶部,因此在比较发生之前sql_variant会隐式转换为字符串文字。sql_variant

\n

比较规则包括(sql_variant强调):

\n
\n
    \n
  • 当比较不同基本数据类型的 sql_variant 值并且基本数据类型属于不同数据类型系列时,层次结构图中数据类型系列较高的值被视为两个值中较大的一个。
  • \n
  • 当比较不同基本数据类型的 sql_variant 值并且基本数据类型属于同一数据类型族时,层次结构图中基本数据类型较低的值将隐式转换为其他数据类型,然后进行比较。
  • \n
  • 当比较 char、varchar、nchar 或 nvarchar 数据类型的 sql_variant 值时,首先根据以下条件比较它们的排序规则:LCID、LCID 版本、比较标志和排序 ID。每个标准都作为整数值进行比较,并按列出的顺序进行比较。如果所有这些条件都相等,则根据排序规则比较实际的字符串值。
  • \n
\n
\n

这解释了您看到的结果。

\n

此外:

\n
\n

处理 sql_variant 数据类型时,SQL Server 支持将其他数据类型的对象隐式转换为 sql_variant 类型。但是,SQL Server 不支持从 sql_variant 数据到其他数据类型的对象的隐式转换。

\n
\n

排序规则优先级的规则是单独的。它们在比较具有不同排序规则标签的字符串时适用。有关Coercible-defaultImplicit XExplicit XNo-collat​​ion标签的详细信息,请参阅链接文档。

\n

使用当前数据库的排序规则将返回值转换sql_variant为基本类型。这将匹配分配给文字值的排序规则,该排序规则应具有 N 前缀才能解释为 Unicode。

\n

就我而言,这意味着:

\n
IF CONVERT(nvarchar(128), SERVERPROPERTY(\'Edition\')) COLLATE DATABASE_DEFAULT = \n    N\'Developer Edition (64-bit)\'\n
Run Code Online (Sandbox Code Playgroud)\n

如果您完全按照预期提供字符串文字,则该子句COLLATE并不是绝对必要的,但您确实要求“最佳”方式,我认为这意味着“最全面”。

\n

我的捷克朋友 Tom\xc3\xa1\xc5\xa1 Z\xc3\xadka 在Expecting Subvertations中写了有关此问题和相关问题的文章。

\n