有没有比更改每一列更简单的方法来解决 SQL Server/数据库排序规则不匹配的问题?

有没有比更改每一列更简单的方法来解决 SQL Server/数据库排序规则不匹配的问题?

免责声明:我知道这个问题之前已经被问过一百次了,但我只是想检查一下,在我继续编写/获取大量代码来完成此操作之前,是否还有我可能错过的更简单的解决方案。

我们的软件使用最初为 SQL Server 7 设计的数据库,因此,创建它的所有脚本都不会为任何字符列指定任何显式排序规则。相反,当创建/恢复数据库到 SQL Server 2000 或更高版本时,每个列都会继承数据库排序规则(恰好如此,SQL_Latin1_General_CP1_CI_AS因为这是 SQL Server 7 的默认设置)。

理论上,这不会有太大影响,因为如果我们的数据库是在客户的服务器上从头创建的,它会继承客户的服务器排序规则(通常是现代安装默认设置Latin1_General_CP1_CI_AS),并且一切都会正常工作。但是,当他们向我们发送数据库备份或我们向他们发送数据库备份时,这种情况就会失效,并且每当代码尝试访问临时表等时,我们或他们都会收到可怕的排序规则不匹配错误。

我们曾尝试教育客户安装或重建他们的 SQL Server 实例以使用我们首选的排序规则,但当然这并不总是发生,也不总是可能的。

创建新数据库并复制数据的解决方案对我们来说并不实用,我们需要一根“魔杖”,我们可以挥动它来实时纠正所有列,而不会干扰数据。我正在考虑编写一个实用程序来执行此操作,但由于这将是一项相当大的工作,有人有什么更简单的建议吗?

答案1

一个选择就是“证明”你的代码不存在排序不匹配的情况。

您可以使用特殊排序规则“DATABASE_DEFAULT”进行强制,而无需知道实际排序规则是什么。您可以在需要使用的临时表、表变量和系统表中的 char 类型列上使用它。

例子:

CREATE TABLE #Currency (CCY CHAR(3))
GO
INSERT #Currency VALUES ('GBP')
INSERT #Currency VALUES ('CHF')
INSERT #Currency VALUES ('EUR')
GO
SELECT Something
FROM myTable M JOIN #Currency C ON M.CCY = C.CCY --error!
GO
-- in join too
SELECT Something
FROM myTable M JOIN #Currency C ON M.CCY = C.CCY COLLATE DATABASE_DEFAULT --no error
GO
DROP TABLE #Currency
GO


CREATE TABLE  #Currency (CCY CHAR(3) COLLATE DATABASE_DEFAULT)
GO
INSERT #Currency VALUES ('GBP')
INSERT #Currency VALUES ('CHF')
INSERT #Currency VALUES ('EUR')
GO
SELECT Something
FROM myTable M JOIN #Currency C ON M.CCY = C.CCY --no error!
GO

DROP TABLE #Currency
GO

这也意味着,当您的客户将他们的数据库迁移到具有另一个不同排序规则的新的 SQL Server 框中时,它也可以工作......

答案2

简而言之,没有简单的方法。我以前也遇到过同样的问题。

我想说的是两件事,首先,当您的客户向您发送一个具有意外排序规则的数据库时,请安装一个与其数据库匹配的默认排序规则的新 SQL 实例,并在其中使用它。

第二,确保您的应用程序可以使用除默认排序规则之外的其他排序规则(因为这些排序规则将来可能会发生变化),并且只要 SQL 服务器和数据库上的排序规则匹配,应用程序就可以正常工作。然后,让客户使用与其数据库匹配的排序规则安装 SQL 服务器并正常工作就相当容易了。

或者编写一个实用程序来更新数据库中的所有表等,正如您所说,但这可能比您想要的要多。

答案3

如果数据库中所有列都采用相同的排序规则,那么在进行跨数据库查询时(或者您的应用程序对排序顺序敏感)只会给您带来问题。

当您意识到临时表的连接是跨数据库的,就像在 tempdb 中一样时,棘手的问题就出现了。不过,这很容易排序 - 只需确保临时表中的任何文本列都是使用该COLLATE database_default指令明确创建的。这意味着将使用当前数据库的默认排序规则而不是 tempdb 的默认集合(与服务器的默认值相同)来创建该列。

相关内容