临时表排序冲突 - 错误:无法解决Latin1*和SQL_Latin1*之间的排序冲突。

34

我无法更新临时表。以下是我的查询语句

CREATE TABLE #temp_po(IndentID INT, OIndentDetailID INT, OD1 VARCHAR(50), OD2 VARCHAR(50), 
        OD3 VARCHAR(50), ORD VARCHAR(50), NIndentDetailID INT, ND1 VARCHAR(50), ND2 VARCHAR(50), 
        ND3 VARCHAR(50), NRD VARCHAR(50), Quantity DECIMAL(15,3))

        INSERT INTO #temp_po(IndentID, OIndentDetailID, OD1, OD2, OD3, ORD)
        SELECT ID.IndentID, ID.IndentDetailID, ID.D1, ID.D2, ID.D3, ID.RandomDimension 
        FROM STR_IndentDetail ID WHERE ID.IndentID = @IndentID

        UPDATE 
            t 
        SET
            t.ND1 = CASE WHEN D.D1 = '' THEN NULL ELSE D.D1 END,
            t.ND2 = CASE WHEN D.D2 = '' THEN NULL ELSE D.D2 END,
            t.ND3 = CASE WHEN D.D3 = '' THEN NULL ELSE D.D3 END,
            t.NRD = CASE WHEN D.RandomDim = '' THEN NULL ELSE D.RandomDim END,
            t.Quantity = D.PurchaseQty
        FROM
            #temp_po t INNER JOIN @detail D ON D.IndentDetailID = t.OIndentDetailID
        WHERE
            t.IndentID = @IndentID

但是它会报错

无法解决"Latin1_General_CI_AI"和"SQL_Latin1_General_CP1_CI_AS"之间的排序冲突,因为它们在等于操作中不兼容。

如何解决这个问题?

我的tempdb排序规则是Latin1_General_CI_AI,而我的实际数据库排序规则是SQL_Latin1_General_CP1_CI_AS


3
正如@StuartLC在下面所说的,这是由于您的列排序规则(很可能是从数据库继承的)与主数据库之间的冲突,因为tempdb默认使用主数据库的排序规则。 最简单的解决方法是将COLLATE DATABASE_DEFAULT附加到每个(n)char/(n)varchar数据类型,以便临时表始终创建匹配您正在使用的数据库。 - Kahn
4个回答

56
这是因为#tempdb.temp_po.OD1STR_IndentDetail.D1的排序规则不同(特别注意,#tempdb是一个不同的系统数据库,通常会有默认的排序规则,而你自己的数据库和表可能会提供更具体的排序规则)。
由于您可以控制临时表的创建,最简单的解决方法似乎是在临时表中创建*char列,并使用与STR_IndentDetail表相同的排序规则。
CREATE TABLE #temp_po(
    IndentID INT, 
    OIndentDetailID INT, 
    OD1 VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS, 
    .. Same for the other *char columns   

当您无法控制表的创建时,在联接列时,另一种方法是在发生错误的DML中添加明确的COLLATE语句,可以通过COLLATE SQL_Latin1_General_CP1_CI_AS或更简单地使用COLLATE DATABASE_DEFAULT

SELECT * FROM #temp_po t INNER JOIN STR_IndentDetail s 
   ON t.OD1 = s.D1 COLLATE SQL_Latin1_General_CP1_CI_AS;

或者,更简单的方法

SELECT * FROM #temp_po t INNER JOIN STR_IndentDetail s 
   ON t.OD1 = s.D1 COLLATE DATABASE_DEFAULT;

SqlFiddle here


相关文章请点击此处 http://www.mssqltips.com/sqlservertip/2440/create-sql-server-temporary-tables-with-the-correct-collation/ - Andrey Belykh

8

更改服务器排序规则并不是一项直接的决定,因为服务器上可能有其他数据库会受到影响。甚至对于一个已存在的已填充数据库,更改数据库排序规则也并非总是明智的选择。我认为,在创建临时表时使用 COLLATE DATABASE_DEFAULT 是最安全、最简单的选项,因为它不会在你的SQL中硬编码任何排序规则。例如:

CREATE TABLE #temp_table1
(
    column_1    VARCHAR(2)  COLLATE database_default
)

0

默认情况下,临时表采用服务器的排序规则。因此,不要更新所有存储过程中的临时表,只需更改服务器排序规则即可。

请查看此链接设置或更改服务器排序规则

这对我很有用。


0
我们现在遇到了同样的问题。我们没有将排序规则添加到临时表创建(或每个临时表连接)中,而是将临时表创建更改为表变量声明。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接