【问题标题】:Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation无法解决等于操作中“SQL_Latin1_General_CP1_CI_AS”和“Latin1_General_CI_AS”之间的排序规则冲突
【发布时间】:2010-12-09 02:49:24
【问题描述】:

我有以下代码

SELECT tA.FieldName As [Field Name],
       COALESCE(tO_A.[desc], tO_B.[desc], tO_C.Name, tA.OldVAlue) AS [Old Value],
       COALESCE(tN_A.[desc], tN_B.[desc], tN_C.Name, tA.NewValue) AS [New Value],
       U.UserName AS [User Name],
       CONVERT(varchar, tA.ChangeDate) AS [Change Date] 
  FROM D tA
       JOIN 
       [DRTS].[dbo].[User] U 
         ON tA.UserID = U.UserID
       LEFT JOIN 
       A tO_A 
         on tA.FieldName = 'AID' 
        AND tA.oldValue = CONVERT(VARCHAR, tO_A.ID)
       LEFT JOIN 
       A tN_A 
         on tA.FieldName = 'AID' 
        AND tA.newValue = CONVERT(VARCHAR, tN_A.ID)
       LEFT JOIN 
       B tO_B 
         on tA.FieldName = 'BID' 
        AND tA.oldValue = CONVERT(VARCHAR, tO_B.ID)
       LEFT JOIN 
       B tN_B 
         on tA.FieldName = 'BID' 
        AND tA.newValue = CONVERT(VARCHAR, tN_B.ID)
       LEFT JOIN 
       C tO_C 
         on tA.FieldName = 'CID' 
        AND tA.oldValue = tO_C.Name
       LEFT JOIN 
       C tN_C 
         on tA.FieldName = 'CID' 
        AND tA.newValue = tN_C.Name
 WHERE U.Fullname = @SearchTerm
ORDER BY tA.ChangeDate

运行代码时,在为表 C 添加两个连接后,我在标题中粘贴了错误。我认为这可能与我使用 SQL Server 2008 并已恢复此副本的事实有关db 到我 2005 年的机器上。

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    您的表中有两个不同的排序规则不匹配。您可以使用以下查询检查表中每列的排序规则:

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

    排序和比较字符串时需要和使用排序规则。在整个数据库中使用单一、唯一的排序规则通常是个好主意 - 不要在单个表或数据库中使用不同的排序规则 - 你只是在自找麻烦......

    一旦您确定了一个排序规则,您就可以使用以下命令更改那些不匹配的表/列:

    ALTER TABLE YourTableName
      ALTER COLUMN OffendingColumn
        VARCHAR(100) COLLATE Latin1_General_CI_AS NOT NULL
    

    马克

    更新:要在您的数据库中查找全文索引,请在此处使用此查询:

    SELECT
        fti.object_Id,
        OBJECT_NAME(fti.object_id) 'Fulltext index',
        fti.is_enabled,
        i.name 'Index name',
        OBJECT_NAME(i.object_id) 'Table name'
    FROM 
        sys.fulltext_indexes fti
    INNER JOIN 
        sys.indexes i ON fti.unique_index_id = i.index_id
    

    然后您可以使用以下方法删除全文索引:

    DROP FULLTEXT INDEX ON (tablename)
    

    【讨论】:

    • 谢谢马克,这正是我正在寻找的东西的类型,其中一张表是不同的排序规则,因为一些愚蠢的原因!我将尝试更改为标准排序规则,看看会发生什么。
    • marc 我现在明白了:无法更改或删除列,因为它已启用全文搜索。
    • 在这种情况下,您需要暂时删除该表上的全文索引,更改排序规则,然后再次重新创建全文索引
    • 感谢 OP,我正在设置一个临时表,所以这有帮助,但由于我无法更改表,我需要正确声明它以开始(如下所示):DECLARE @Table TABLE (CompareMessage VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
    • 为什么我们不能在同一张桌子上有 2 个不同的排序规则。如果我有 1 列作为 nvarchar,它只需要英文名称和其他列作为俄文字母,其他列作为日文字母。我该如何安排?是否有一个排序规则涵盖所有这些?
    【解决方案2】:

    我之前也遇到过这样的情况,我们发现两张表之间的排序规则不同。

    检查这些是否相同。

    【讨论】:

      【解决方案3】:

      在查询中使用collate 子句:

      LEFT JOIN C tO_C on tA.FieldName = 'CID' AND tA.oldValue COLLATE Latin1_General_CI_AS = tO_C.Name  
      

      我的语法可能不完全正确(检查 BOL),但您可以这样做以动态更改查询的排序规则 - 您可能需要为每个连接添加子句。

      编辑:我意识到这不太正确 - collat​​e 子句位于您需要更改的字段之后 - 在此示例中,我更改了 tA.oldValue 字段的排序规则。

      【讨论】:

        【解决方案4】:

        我执行以下操作:

        ...WHERE 
            fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT
        

        每次都有效。 :)

        【讨论】:

        • 这是 SO 上最有用的帖子之一
        • 使用此解决方案是因为我正在使用相同的数据库处理两个旧系统,因此我不确定更改表的排序规则是否会破坏功能。
        • 如果相同的两个字段在其他地方一起使用(比较、联合、合并等),请确保每个字段都指定了排序规则。
        • 这非常有用。我正在使用本地数据库并查询链接服务器,它们有两种不同的排序规则。显然我无法更改链接服务器上的排序规则,并且我不想在本地更改我的,所以这绝对是最好的答案。
        • @ppumkin 虽然这是一个很好的解决方案,但它仍然只是避免问题,而不是解决问题。除非您想更改每个查询的排序规则,否则这很乏味且性能不佳。虽然这是一个很好的答案,但我认为公认的答案更好。
        【解决方案5】:

        根本原因是您从中获取架构的 sql server 数据库的排序规则与您的本地安装不同。如果您不想担心排序规则,请使用与 SQL Server 2008 数据库相同的排序规则在本地重新安装 SQL Server。

        【讨论】:

        • 遇到同样的问题,你首先需要检查你的服务器和数据库属性,看看它们是否有相同的排序规则
        【解决方案6】:

        对于导致此问题的数据库具有 CREATE DATABASE 脚本(如我的情况)的用户,您可以使用以下 CREATE 脚本来匹配排序规则:

        -- Create Case Sensitive Database
        CREATE DATABASE CaseSensitiveDatabase
        COLLATE SQL_Latin1_General_CP1_CS_AS -- or any collation you require
        GO
        USE CaseSensitiveDatabase
        GO
        SELECT *
        FROM sys.types
        GO
        --rest of your script here
        

        -- Create Case In-Sensitive Database
        CREATE DATABASE CaseInSensitiveDatabase
        COLLATE SQL_Latin1_General_CP1_CI_AS -- or any collation you require
        GO
        USE CaseInSensitiveDatabase
        GO
        SELECT *
        FROM sys.types
        GO
        --rest of your script here
        

        这会将所需的排序规则应用于所有表,这正是我所需要的。对于服务器上的所有数据库,最好尝试保持相同的排序规则。 希望这会有所帮助。

        更多信息请点击以下链接:SQL SERVER – Creating Database with Different Collation on Server

        【讨论】:

          【解决方案7】:

          当我使用旧的 jdbc 驱动程序时,我遇到了类似的错误(无法解决 INTERSECT 操作中“SQL_Latin1_General_CP1_CI_AS”和“SQL_Latin1_General_CP1250_CI_AS”之间的排序规则冲突)。

          我通过从Microsoft 或开源项目jTDS 下载新驱动程序解决了这个问题。

          【讨论】:

            【解决方案8】:

            这就是我们所做的,在我们的情况下,我们需要使用按需日期限制来执行临时查询,并且查询是在表中定义的。

            我们的新查询需要匹配不同数据库之间的数据,并包含来自这两个数据库的数据。

            从 iSeries/AS400 系统导入数据的数据库和我们的报告数据库之间的 COLLATION 似乎不同 - 这可能是因为特定的数据类型(例如名称上的希腊重音等)。

            所以我们使用了下面的连接子句:

            ...LEFT Outer join ImportDB..C4CTP C4 on C4.C4CTP COLLATE Latin1_General_CS_AS=CUS_Type COLLATE Latin1_General_CS_AS
            

            【讨论】:

              【解决方案9】:

              确定引发此错误的字段并添加以下内容: 整理数据库_DEFAULT

              在代码字段上连接了两个表:

              ...
              and table1.Code = table2.Code
              ...
              

              将您的查询更新为:

              ...
              and table1.Code COLLATE DATABASE_DEFAULT = table2.Code COLLATE DATABASE_DEFAULT
              ...
              

              【讨论】:

                【解决方案10】:

                感谢 marc_s 的回答,我解决了我最初的问题 - 启发我更进一步并发布一种方法来一次转换整个表 - tsql 脚本来生成更改列语句:

                DECLARE @tableName VARCHAR(MAX)
                SET @tableName = 'affiliate'
                --EXEC sp_columns @tableName
                SELECT  'Alter table ' + @tableName + ' alter column ' + col.name
                        + CASE ( col.user_type_id )
                            WHEN 231
                            THEN ' nvarchar(' + CAST(col.max_length / 2 AS VARCHAR) + ') '
                          END + 'collate Latin1_General_CI_AS ' + CASE ( col.is_nullable )
                                                                    WHEN 0 THEN ' not null'
                                                                    WHEN 1 THEN ' null'
                                                                  END
                FROM    sys.columns col
                WHERE   object_id = OBJECT_ID(@tableName)
                

                得到: ALTER TABLE Affiliate ALTER COLUMN myTable NVARCHAR(4000) COLLATE Latin1_General_CI_AS NOT NULL

                我承认对 col.max_length / 2 的需要感到困惑 -

                【讨论】:

                • 我认为需要除以二,因为长度在内部存储为字节数。 Nvarchar 每个字符占用两个字节,而不是 varchar。
                • 干得好,ncha 数据类型的查询剂量计数可能是因为 col.max_length / 2 -
                【解决方案11】:

                当您有 2 个不同的数据库,特别是来自 2 个不同服务器的 2 个不同数据库时,这很容易发生。最好的选择是将其更改为通用集合并进行连接或比较。

                SELECT 
                   *
                FROM sd
                INNER JOIN pd ON sd.SCaseflowID COLLATE Latin1_General_CS_AS = pd.PDebt_code COLLATE Latin1_General_CS_AS
                

                【讨论】:

                  【解决方案12】:
                  ALTER DATABASE test2            --put your database name here
                  COLLATE Latin1_General_CS_AS    --replace with the collation you need
                  

                  【讨论】:

                    【解决方案13】:

                    我已使用此 site 中的内容创建了以下脚本,该脚本更改了所有表中所有列的排序规则:

                    CREATE PROCEDURE [dbo].[sz_pipeline001_collation] 
                        -- Add the parameters for the stored procedure here
                    AS
                    BEGIN
                        -- SET NOCOUNT ON added to prevent extra result sets from
                        -- interfering with SELECT statements.
                        SET NOCOUNT ON;
                    
                    
                    SELECT 'ALTER TABLE [' + SYSOBJECTS.Name + '] ALTER COLUMN [' + SYSCOLUMNS.Name + '] ' +
                    SYSTYPES.name + 
                        CASE systypes.NAME
                        WHEN 'text' THEN ' '
                        ELSE
                        '(' + RTRIM(CASE SYSCOLUMNS.length
                        WHEN -1 THEN 'MAX'
                        ELSE CONVERT(CHAR,SYSCOLUMNS.length)
                        END) + ') ' 
                        END
                    
                        + ' ' + ' COLLATE Latin1_General_CI_AS ' + CASE ISNULLABLE WHEN 0 THEN 'NOT NULL' ELSE 'NULL' END
                        FROM SYSCOLUMNS , SYSOBJECTS , SYSTYPES
                        WHERE SYSCOLUMNS.ID = SYSOBJECTS.ID
                        AND SYSOBJECTS.TYPE = 'U'
                        AND SYSTYPES.Xtype = SYSCOLUMNS.xtype
                        AND SYSCOLUMNS.COLLATION IS NOT NULL
                        AND NOT ( sysobjects.NAME LIKE 'sys%' )
                        AND NOT ( SYSTYPES.name LIKE 'sys%' )
                    
                    END
                    

                    【讨论】:

                    • SYSCOLUMNS.length of nvarchar 列必须除以 2
                    【解决方案14】:

                    您可以通过 4 个简单的步骤轻松做到这一点

                    1. 备份您的数据库,以防万一
                    2. 更改数据库排序规则:右键单击数据库,选择属性,转到选项并将排序规则更改为所需的排序规则。
                    3. 生成脚本以删除和重新创建所有数据库对象:右键单击数据库,选择任务,选择生成脚本...(确保在向导的高级选项中选择删除和​​创建,同时选择架构和数据)
                    4. 运行上面生成的脚本

                    【讨论】:

                      【解决方案15】:

                      @Valkyrie 很棒的答案。当我在存储过程中对子查询执行相同的操作时,我想在这里放置一个案例,因为我想知道您的答案在这种情况下是否有效,而且效果很棒。

                      ...WHERE fieldname COLLATE DATABASE_DEFAULT in (
                                SELECT DISTINCT otherfieldname COLLATE DATABASE_DEFAULT
                                FROM ...
                                WHERE ...
                              )
                      

                      【讨论】:

                        【解决方案16】:

                        检查不匹配的排序规则级别(服务器、数据库、表、列、字符)。

                        如果是服务器,这些步骤帮了我一次:

                        1. 停止服务器
                        2. 找到您的 sqlservr.exe 工具
                        3. 运行这个命令:

                          sqlservr -m -T4022 -T3659 -s"name_of_insance" -q "name_of_collation"

                        4. 启动你的 sql 服务器:

                          net start name_of_instance

                        5. 再次检查服务器的排序规则。

                        这里有更多信息:

                        https://www.mssqltips.com/sqlservertip/3519/changing-sql-server-collation-after-installation/

                        【讨论】:

                          【解决方案17】:

                          error (Cannot resolve the collat​​ion conflict between .... ) 通常在比较多个数据库的数据时发生。

                          由于您现在无法更改数据库的排序规则,请使用 COLLATE DATABASE_DEFAULT。

                          ----------
                          AND db1.tbl1.fiel1 COLLATE DATABASE_DEFAULT =db2.tbl2.field2 COLLATE DATABASE_DEFAULT 
                          

                          【讨论】:

                          【解决方案18】:

                          如果这发生在整个数据库中,那么最好像这样更改数据库排序规则:

                          USE master;  
                          GO  
                          ALTER DATABASE MyOptionsTest  
                          COLLATE << INSERT COLATION REQUIRED >> ;  
                          GO  
                          
                          --Verify the collation setting.  
                          SELECT name, collation_name  
                          FROM sys.databases  
                          WHERE name = N'<< INSERT DATABASE NAME >>';  
                          GO 
                          

                          参考here

                          【讨论】:

                          • 不幸的是,这不会更改现有表的排序规则,而只会更改新表的默认值
                          【解决方案19】:
                          INSERT INTO eSSLSmartOfficeSource2.[dbo].DeviceLogs  (DeviceId,UserId,LogDate,UpdateFlag) 
                          SELECT DL1.DeviceId ,DL1.UserId COLLATE DATABASE_DEFAULT,DL1.LogDate 
                          ,0 FROM eSSLSmartOffice.[dbo].DeviceLogs DL1 
                          WHERE  NOT EXISTS 
                          (SELECT DL2.DeviceId ,DL2.UserId COLLATE DATABASE_DEFAULT
                          ,DL2.LogDate ,DL2.UpdateFlag 
                          FROM eSSLSmartOfficeSource2.[dbo].DeviceLogs DL2    
                          WHERE  DL1.DeviceId =DL2.DeviceId
                           and DL1.UserId collate  Latin1_General_CS_AS=DL2.UserId collate  Latin1_General_CS_AS
                            and DL1.LogDate =DL2.LogDate )
                          

                          【讨论】:

                            【解决方案20】:

                            在 where 条件中添加collate SQL_Latin1_General_CP1_CI_AS

                            这对我有用。

                            WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS
                            

                            【讨论】:

                              【解决方案21】:

                              在@JustSteve 的回答中添加了处理 varchar 和 varchar(MAX) 列的代码:

                              DECLARE @tableName VARCHAR(MAX)
                              SET @tableName = 'first_notes'
                              --EXEC sp_columns @tableName
                              SELECT  'Alter table ' + @tableName + ' alter column ' + col.name
                                      + CASE ( col.user_type_id )
                                          WHEN 231
                                          THEN ' nvarchar(' + CAST(col.max_length / 2 AS VARCHAR) + ') '
                                          WHEN 167
                                          THEN ' varchar(' + CASE col.max_length 
                                                              WHEN -1 
                                                              THEN 'MAX'
                                                              ELSE 
                                                              CAST(col.max_length AS VARCHAR)
                                                              end
                                                               + ') '
                                        END + 'collate Latin1_General_CI_AS ' + CASE ( col.is_nullable )
                                                                                  WHEN 0 THEN ' not null'
                                                                                  WHEN 1 THEN ' null'
                                                                                END
                              FROM    sys.columns col
                              WHERE   object_id = OBJECT_ID(@tableName)
                              

                              【讨论】:

                                【解决方案22】:

                                您的数据库中可能没有任何排序规则问题,但如果您从具有与原始排序规则不同的排序规则的服务器上的备份中恢复数据库副本,并且您的代码正在创建临时表,那么这些临时表将从服务器继承排序规则,会与您的数据库发生冲突。

                                【讨论】:

                                  【解决方案23】:

                                  要在不更改任一数据库的情况下解决查询中的此问题,您可以将表达式转换为“=”符号的另一侧

                                  COLLATE SQL_Latin1_General_CP1_CI_AS
                                  

                                  按照here的建议。

                                  【讨论】:

                                    【解决方案24】:

                                    我也有类似的要求;在这里为任何有类似情况的人记录我的方法...

                                    场景

                                    • 我有一个全新安装的具有正确排序规则的数据库。
                                    • 我的另一个数据库有错误的排序规则。
                                    • 我需要更新后者以使用前者定义的排序规则。

                                    解决方案

                                    使用 SQL Server 架构比较(来自 SQL Server Data Tools / Visual Studio)将源(全新安装)与目标(排序规则无效的数据库)进行比较。

                                    就我而言,我直接比较了两个数据库;虽然你可以通过一个项目来手动调整它们之间的部分......

                                    • 运行 Visual Studio
                                    • 创建新的 SQL Server 数据项目
                                    • 单击工具、SQL Server、新架构比较
                                    • 选择源数据库
                                    • 选择目标数据库
                                    • 单击选项 (⚙)
                                      • Object Types 下仅选择您感兴趣的类型(对我来说只有ViewsTables
                                      • General 下选择:
                                        • 阻止可能的数据丢失
                                        • 禁用和重新启用 DDL 触发器
                                        • 忽略加密提供程序文件路径
                                        • 忽略文件和日志文件路径
                                        • 忽略文件大小
                                        • 忽略文件组放置
                                        • 忽略全文目录文件路径
                                        • 忽略关键字大小写
                                        • 忽略登录 SID
                                        • 忽略带引号的标识符
                                        • 忽略路由生命周期
                                        • 忽略语句之间的分号
                                        • 忽略空格
                                        • 脚本刷新模块
                                        • 新约束的脚本验证
                                        • 验证排序规则兼容性
                                        • 验证部署
                                    • 点击比较
                                      • 取消选中标记为删除的任何对象(注意:这些对象可能仍然存在排序规则问题;但由于它们没有在我们的源/模板数据库中定义,我们不知道;无论哪种方式,我们都不想丢失任何东西,如果我们只针对排序规则更改)。您可以通过右键单击 DELETE 文件夹并选择 EXCLUDE 来一次性取消选中。
                                      • 同样排除任何 CREATE 对象(这里因为它们不存在于目标中,所以它们不能在那里有错误的排序规则;它们是否应该存在是另一个主题的问题)。
                                      • 单击更改下的每个对象以查看该对象的脚本。使用 diff 确保我们只更改排序规则(手动检测到的任何其他差异,您可能希望手动排除/处理这些对象)。
                                    • 点击Update推送更改

                                    这仍然需要一些手动操作(例如,检查您是否只影响排序规则) - 但它会为您处理依赖关系。

                                    您还可以保留一个有效架构的数据库项目,这样如果您有超过 1 个要更新的数据库,您就可以为您的数据库使用通用模板,假设所有目标数据库最终都应该具有相同的架构。

                                    如果您希望在数据库项目中批量修改设置,您还可以对数据库项目中的文件使用查找/替换(例如,您可以使用架构比较从无效数据库创建项目,修改项目文件,然后切换源架构中的 /target 比较以将您的更改推回数据库)。

                                    【讨论】:

                                      猜你喜欢
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2016-05-28
                                      • 1970-01-01
                                      • 2011-01-04
                                      • 2018-10-20
                                      相关资源
                                      最近更新 更多