SQL排序规则与来自 Delphi 应用程序的临时表和过程参数冲突

e5nszbig  于 2023-02-08  发布在  其他
关注(0)|答案(3)|浏览(126)

我使用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子句时,它工作。2当我离开它时(尽管它只与一个表比较参数),它失败了。

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

过程参数声明如下:@部件ID字符(30)、@位置整数、@订单号字符(8)、@LN字符(2)、@DL字符(2)、@父ID字符(30)、@修改位输出
我在这里找到了一个解决方案:Cannot resolve the collation 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')

除了DB级和列级之外,还有其他地方可以设置排序规则吗?
我想知道发生了什么事...

2vuwiymt

2vuwiymt1#

排序规则冲突出现在任何比较不同排序规则的字符串的运算符上,例如select中的equals。
TempDb采用服务器默认排序规则,而您的真实的Db可能有不同的排序规则,这导致使用DDL创建的任何临时表都有排序规则差异。
您可以在相等运算符之后添加“collate database_default”子句,这样就可以修复它。或者您可以使用以下命令创建临时表:

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

这将强制临时表列从您的数据库中获取数据类型(& collation)。

e0uiprwp

e0uiprwp2#

有一个服务器级别的排序规则设置作为所有系统数据库的默认值。有一个数据库级别的排序规则,正如你所说的。列和表达式可以有一个定义的排序规则。
当数据库与系统数据库(尤其是tempdb)具有不同的排序规则时,会出现许多问题。
我不想重复Peter Wishart的回答(我同意他的回答),我只想补充一点:在开发产品时,您应该决定您将允许什么级别的排序灵活性。为了避免问题,您必须围绕该选择设计代码。如果您不打算要求您的数据库对象与服务器排序一致,然后,您必须应用排序规则修饰符或控制在tempdb中创建表、使用系统表或进行比较时使用的排序规则。在大型产品中,这可能是大量代码。
在SQLServer中还有另一个排序规则经常被忽略。这是任何.Net SP或函数中使用的默认排序规则。该排序规则是基于SQLServer进程的windows用户配置文件定义的。在文档中通常不称为排序规则,它是windows区域设置的一部分。在注册表中称为LCID。
因此,即使数据库、sqlserver、表、列排序规则都匹配,如果在CLR存储过程代码中进行字符串比较,仍然可能会出现不匹配,除非编写代码来避免这种情况。

u91tlkcl

u91tlkcl3#

若要解决排序规则冲突,请在“=”运算符周围添加 “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

相关问题