【问题标题】: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\" 之间的归类冲突
【发布时间】:2023-01-05 22:42:30
【问题描述】:

我有以下代码

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 并将此数据库的副本还原到我的机器是2005年的。

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    我执行以下操作:

    ...WHERE 
        fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT
    

    每次都有效。 :)

    【讨论】:

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

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

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

    在查询中使用 collate 子句:

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

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

    编辑:我意识到这不太正确——排序规则在你需要更改的字段之后——在这个例子中,我更改了tA.oldValue字段的排序规则。

    【讨论】:

      【解决方案4】:

      确定引发此错误的字段并向其添加以下内容: 整理 DATABASE_DEFAULT

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

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

      将您的查询更新为:

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

      【讨论】:

        【解决方案5】:

        当您有 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
        

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

            在 where 条件中添加 collate SQL_Latin1_General_CP1_CI_AS

            这对我有用。

            WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS
            

            【讨论】:

              【解决方案8】:

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

              COLLATE SQL_Latin1_General_CP1_CI_AS
              

              按照建议here

              【讨论】:

                【解决方案9】:

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

                【讨论】:

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

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

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

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

                【讨论】:

                【解决方案11】:

                我以前有过这样的事情,我们发现2个表之间的排序规则不同。

                检查它们是否相同。

                【讨论】:

                  【解决方案12】:

                  多亏了 marc_s 的回答,我解决了我最初的问题 - 启发我更进一步并发布了一种一次转换整个表的方法 - 用于生成 alter column 语句的 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) 整理 Latin1_General_CI_AS NOT NULL

                  我承认我对需要col.max_length / 2-

                  【讨论】:

                  • 我认为除以二是必需的,因为长度在内部存储为字节数。 Nvarchar 每个字符需要两个字节,而不是 varchar 一个字节。
                  • 伟大的工作,可能是因为 col.max_length / 2 -
                  【解决方案13】:

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

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

                  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/

                  【讨论】:

                    【解决方案14】:

                    我已经使用 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.nvarchar 列的长度必须除以 2
                    【解决方案15】:

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

                    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

                    【讨论】:

                    • 不幸的是,这不会更改现有表的排序规则,而只会更改新表的默认排序规则
                    【解决方案16】:

                    对于那些拥有导致此问题的数据库的 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

                    【讨论】:

                      【解决方案17】:

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

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

                      【讨论】:

                        【解决方案18】:
                        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 )
                        

                        【讨论】:

                          【解决方案19】:

                          在@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)
                          

                          【讨论】:

                            【解决方案20】:

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

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

                            【讨论】:

                              【解决方案21】:

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

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

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

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

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

                              【讨论】:

                                【解决方案22】:

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

                                【讨论】:

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

                                  【讨论】:

                                    【解决方案24】:

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

                                    设想

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

                                    解决方案

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

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

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

                                    这仍然涉及一些手动工作(例如,检查您是否只影响整理)——但它会为您处理依赖项。

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

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

                                    【讨论】:

                                      【解决方案25】:

                                      到目前为止,我几乎阅读了这里的每一个答案和评论。通过结合所做的响应,它让我找到了一个简单的解决方案。所以这就是我很容易解决的问题:

                                      1. 创建数据库脚本。右键单击数据库 > 任务 > 生成脚本。一定要包括架构和数据
                                      2. 保存脚本后删除数据库。右键单击数据库 > 删除
                                      3. 删除脚本中将重新创建数据库的部分,即删除以以下内容开头的第一行之前的所有内容:

                                        使用 < 数据库名称 >

                                        1. “手动”创建数据库,即右键单击“表”>“创建数据库...”

                                        2. 运行为新的空数据库设置默认排序规则的脚本。

                                          使用大师;

                                          更改数据库 << 数据库名称 >>

                                          整理 << 需要插入整理 >> ;

                                        3. 运行您保存的脚本以重新创建数据库

                                        归功于

                                        1. @Justin 提供了检查数据库排序规则的脚本,以及如何更新它
                                        2. @RockScience 提到对排序规则的更改将仅适用于新表/对象
                                        3. @Felix Mwiti Mugambi(感谢我的肯尼亚同胞 :))表示需要重新创建数据库。 (我通常避免删除和创建复杂的数据库)

                                      【讨论】:

                                        猜你喜欢
                                        • 1970-01-01
                                        • 2010-12-09
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2016-05-28
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多