在等于操作中无法解决“SQL_Latin1_General_CP1_CI_AS”和“Latin1_General_CI_AS”之间的排序规则冲突

时间:2009-10-22 14:20:13

标签: sql-server

我有以下代码

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年。

24 个答案:

答案 0 :(得分:740)

我执行以下操作:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

每次都有效。 :)

答案 1 :(得分:279)

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

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)

答案 2 :(得分:67)

在查询中使用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字段的排序规则。

答案 3 :(得分:25)

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

代码字段中有两个表连接:

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

将您的查询更新为:

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

答案 4 :(得分:11)

@Valkyrie很棒的答案。以为我在这里提出了一个案例,当一个子查询执行相同的内存存储过程时,因为我想知道你的答案在这种情况下是否有效,并且确实很棒。

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

答案 5 :(得分:10)

在where条件中添加collate SQL_Latin1_General_CP1_CI_AS

这适合我。

WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS

答案 6 :(得分:9)

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

答案 7 :(得分:6)

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

答案 8 :(得分:5)

错误(无法解决....之间的排序规则冲突)通常在比较来自多个数据库的数据时发生。

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

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

答案 9 :(得分:4)

之前我有类似的东西,我们发现两张桌子之间的整理是不同的。

检查这些是否相同。

答案 10 :(得分:3)

感谢marc_s的回答,我解决了我原来的问题 - 受到启发,更进一步,发布了一种方法,一次转换整个表 - tsql脚本生成alter column语句:

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 的需要感到困惑 -

答案 11 :(得分:2)

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

(name, df)

答案 12 :(得分:2)

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

答案 13 :(得分:2)

如果在整个数据库中出现这种情况,那么最好像这样更改数据库归类:

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

答案 14 :(得分:2)

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

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

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

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

  4. 启动sql server:

    net start name_of_instance

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

  6. 以下是更多信息:

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

答案 15 :(得分:2)

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

答案 16 :(得分:1)

您可以通过使用4个简单步骤轻松完成此操作

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

答案 17 :(得分:1)

ALTER DATABASE test2 - 将您的数据库名称放在此处    COLLATE Latin1_General_CS_AS - 替换为您需要的任何排序规则

答案 18 :(得分:1)

这是我们所做的,在我们的情况下,我们需要根据需要使用日期限制执行即席查询,并在表中定义查询。

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

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

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

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

答案 19 :(得分:1)

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 :(得分:1)

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

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

答案 21 :(得分:1)

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

COLLATE SQL_Latin1_General_CP1_CI_AS

如建议的here

答案 22 :(得分:0)

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

答案 23 :(得分:0)

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

场景

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

解决方案

使用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进行比较,以将您的更改推送回数据库)。