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


340

我有以下代码

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

Answers:


306

您的表中有两个不同的排序规则不匹配。您可以使用此查询来检查表中各列具有哪些排序规则:

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,这正是我想要的东西,由于某些愚蠢的原因,其中一张桌子是不同的排序规则!我将尝试更改为标准归类,看看会发生什么。
jhowe

马克我现在得到这个:无法更改或删除列,因为它已启用全文搜索。
jhowe

1
在这种情况下,您需要暂时将全文索引放到该表上,更改排序规则,然后再次重新创建全文索引
marc_s 2009年

1
谢谢OP,我正在建立一个临时表,所以这样做很有帮助,但是由于无法更改该表,我需要正确地声明它才能以(如下所示)开头:DECLARE @Table TABLE(CompareMessage VARCHAR(50)COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII 2014年

1
为什么我们不能在同一张桌子上有2个不同的排序规则。如果我有1列为nvarchar,则仅需要英文名称,另一列为俄语字母,另一列为日文字母。我该如何安排?是否有一个归类涵盖所有这些内容?
batmaci

853

我执行以下操作:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

每次都能工作。:)


68
这是SO上最有用的帖子之一
-Jamie Strauss

2
之所以使用此解决方案,是因为我正在使用同一数据库在两个遗留系统中工作,因此不确定更改表的排序规则是否会破坏功能。
paolobueno 2014年

5
如果在其他地方(比较,联合,合并等)一起使用相同的两个字段,请确保每个字段也都指定了排序规则。
扎里菲斯2014年

5
这是非常有用的。我正在使用本地数据库,并针对链接的服务器进行查询,它们具有两种不同的排序规则。显然,我无法更改链接服务器上的排序规则,也不想在本地更改我的排序规则,因此,这绝对是最佳答案。
jtate 2014年

7
@ppumkin虽然这是一个很好的解决方案,但它只能避免问题,而不能解决问题。除非您要更改每个查询的排序规则,否则这将是乏味且效果不理想的。虽然这是一个很好的答案,但我认为可接受的答案是更好的答案。
罗布

80

collate在查询中使用子句:

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

我的语法可能不太正确(请检查BOL),但是您可以执行此操作以即时更改查询的排序规则-您可能需要为每个联接添加子句。

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


29

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

在“代码”字段中连接了两个表:

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

将查询更新为:

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

谢谢。在生产数据库中工作时,我们不能总是按照公认的答案建议更改数据库结构。
詹妮弗·伍德

20

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

13

@女武神真棒答案。我以为我在这种情况下在存储过程中对子查询执行相同的情况时,我想知道您的答案在这种情况下是否有效,并且确实很棒。

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


6

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


遇到相同的问题,您首先需要检查服务器和数据库属性,以查看它们是否具有相同的归类
madan

5

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

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

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

这与已经给出的另一个答案没有什么不同:stackoverflow.com/a/1607725/479251
Pac0

4

我以前有过类似的事情,我们发现两个表之间的排序规则是不同的。

检查这些是否相同。


4

多亏了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关联ALTER COLUMN myTable NVARCHAR(4000)COLLATE Latin1_General_CI_AS NOT NULL

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


我认为必须除以2,因为长度在内部存储为字节数。Nvarchar每个字符占用两个字节,而不是varchar一个字节。
Zebi

伟大的工作,怎么过上面的查询dosent计数NCHA数据类型,可能是因为col.max_length / 2 -
伊姆兰

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 –在服务器上创建具有不同排序规则的数据库


2

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

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

1
nvarchar列的SYSCOLUMNS.length必须除以2
palota

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. 再次检查服务器的排序规则。

这是更多信息:

https://www.mssqltips.com/sqlservertip/3519/changing-sql-server-collat​​ion-after-installation/


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 

这里参考


不幸的是,这不会更改现有表的排序规则,而只会更改新表的默认排序规则
RockScience

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)


1

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

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


1

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

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

从iSeries / AS400系统导入数据的数据库和我们的报告数据库之间,COLLATION似乎有所不同-这可能是由于特定的数据类型(例如名称上带有希腊字母的重音等)引起的。

因此,我们使用了以下join子句:

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

1

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

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

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 )

0

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


0
ALTER DATABASE test2            --put your database name here
COLLATE Latin1_General_CS_AS    --replace with the collation you need

0

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

情境

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

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

就我而言,我直接比较了两个数据库。虽然您可以通过一个项目来工作,以允许您手动调整之间的片段...

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

这仍然需要一些人工工作(例如,检查您是否正在影响排序规则)-但是它可以为您处理依赖项。

另外,您可以保留有效模式的数据库项目,以便在要更新的对象数大于1的情况下,可以为数据库使用通用模板,假设所有目标DB都应使用相同的模式。

如果您希望大规模修改数据库项目中的设置,也可以在数据库项目的文件上使用查找/替换(例如,这样您可以使用架构比较从无效数据库创建项目,修改项目文件,然后在其中切换源/目标模式进行比较,以将您的更改推回数据库)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.