3

几年来我一直在使用 MS SQL,在我以前的工作中从未遇到过这样的事情。但是在我现在工作的地方,我遇到了一个错误,我真的很想知道原因。

我制作了一个存储过程,并在我的 Delphi 5(是的,我知道)应用程序中使用一些参数调用它。这在两个数据库(不同时间的副本)上运行良好。但是现在我在另一个数据库(又是一个副本)上尝试了它,但它给了我以下错误:

Cannot resolve the collation conflict between "Latin1_General_CI_AS" and 
"SQL_Latin1_General_CP1_CI_AS" in the equal to operation.

我通过创建一个临时表然后尝试插入一些数据来得到这个。我什至不加入。有趣的是:当我删除整个 WHERE 子句时,它就起作用了。当我离开它时(尽管它只将参数与一张表进行比较),它失败了。

create table #TOP (EDAID int, ParentID char(30), ChildID char(30),
    Position int, OrgQty_modified_manually bit)

这失败了:

insert into #TOP
select EDAID, ParentID, ChildID, Position, OrgQty_modified_manually
from EDA_SOBOM
where OrderNr = @OrderNr
    and Position = @Position
    and LN = @LN
    and DL = @DL
    and rtrim(ChildID) = @CurrentPart
    and rtrim(ParentID) = @ParentID

这有效:

insert into #TOP
select EDAID, ParentID, ChildID, Position, OrgQty_modified_manually
from EDA_SOBOM

过程参数声明如下:@PartID char(30)、@Position int、@OrderNr char(8)、@LN char(2)、@DL char(2)、@ParentID char(30)、@Modified bit输出

我在这里找到了解决方案:Cannot resolve the collat​​ion conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation

所以我在 CREATE 之后添加了这个:

ALTER TABLE #TOP
  ALTER COLUMN ParentID
    VARCHAR(30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL

ALTER TABLE #TOP
  ALTER COLUMN ChildID
    VARCHAR(30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL

这使得整个事情再次起作用......但我不明白为什么只有参数比较的 WHERE 子句会失败......参数也可以有排序规则吗?

DB 有排序规则 SQL_Latin1_General_CP1_CI_AS。表 EDA_SOBOM 在 char 列上也有排序规则 SQL_Latin1_General_CP1_CI_AS。我通过以下查询找到了这一点:

SELECT col.name, col.collation_name
FROM sys.columns col
WHERE object_id = OBJECT_ID('EDA_SOBOM')

除了数据库级别和列级别之外,还有其他地方可以设置排序规则吗?

我想知道这是怎么回事...

4

3 回答 3

1

任何比较不同排序规则字符串的运算符都会出现排序规则冲突,即您选择的等号。

TempDb 采用服务器默认排序规则,而您的真实 Db 可能有不同的排序规则,导致使用 DDL 创建的任何临时表都有排序规则差异。

您可以在应该修复它的相等运算符之后添加“collat​​e database_default”子句。或者您可以使用以下方法创建临时表:

select top 0 EDAID, ParentID, ChildID, Position, OrgQty_modified_manually 
into #top
from EDA_SOBOM

这将强制临时表列从您的数据库中获取数据类型(和排序规则)。

于 2012-05-11T07:56:19.590 回答
0

有一个服务器级排序规则设置作为所有系统数据库的默认设置。正如您所说,有一个数据库级别的排序规则。列和表达式可以定义排序规则。

当数据库与系统数据库(尤其是 tempdb)具有不同的排序规则时,会出现许多问题。

在不重复我同意的 Peter Wishart 的回答的情况下,我只想补充一点,在开发产品时,您应该决定要允许的整理灵活性级别。为避免出现问题,您必须围绕该选择设计代码。如果您不要求您的数据库对象与服务器排序规则一致,那么您必须应用排序规则修饰符或控制在 tempdb 中创建表、使用系统表或完成比较时使用的排序规则。这可能是大型产品中的大量代码。

SQLServer 中经常忽略另一种排序规则。这是任何 .Net SP 或函数中使用的默认排序规则。该排序规则是根据 SQLServer 进程的 Windows 用户配置文件定义的。它在文档中通常不称为排序规则,它是 Windows 区域设置的一部分。在注册表中称为 LCID。

因此,即使您的数据库、sqlserver、表、列排序规则都匹配,如果您在 CLR 存储过程代码中进行字符串比较,您仍然可能会出现不匹配,除非您编写该代码来避免它们。

于 2012-05-11T08:13:42.310 回答
0

要解决排序规则冲突,请在“=”运算符周围添加“COLLATE DATABASE_DEFAULT”关键字。

SELECT col.name, col.collation_name
FROM sys.columns col
WHERE object_id COLLATE DATABASE_DEFAULT = OBJECT_ID('EDA_SOBOM') COLLATE DATABASE_DEFAULT

希望这可以帮助...

于 2016-03-20T19:54:49.263 回答