동일 작업에서“SQL_Latin1_General_CP1_CI_AS”와“Latin1_General_CI_AS”의 데이터 정렬 충돌을 해결할 수 없습니다.


345

다음 코드가 있습니다

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입니다.

답변:


307

테이블에 서로 다른 두 데이터 정렬이 일치하지 않습니다. 이 쿼리를 사용하여 테이블의 각 열에 어떤 데이터 정렬이 있는지 확인할 수 있습니다.

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

marc 나는 이것을 얻고있다 : 전체 텍스트 검색에 사용 가능하기 때문에 열을 변경하거나 삭제할 수 없습니다.
jhowe

1
이 경우에는 일시적으로 해당 테이블에 전체 텍스트 인덱스를 삭제 정렬을 변경 한 다음 다시 전체 텍스트 인덱스를 다시 만들어야합니다
marc_s

1
OP 덕분에 임시 테이블을 설정하여 도움이되었지만 테이블을 변경할 수 없으므로 다음과 같이 시작하도록 올바르게 선언해야했습니다 .DECLARE @Table TABLE (CompareMessage VARCHAR (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII 2016 년

1
왜 같은 테이블에 두 개의 다른 데이터 정렬이있을 수 없습니까? nvarchar로 1 열이 있고 영어 이름 만 필요하고 다른 열은 러시아어 문자, 다른 열은 일본어 문자가 필요합니다. 이것을 어떻게 준비합니까? 이 모든 것을 다루는 단일 데이터 정렬이 있습니까?
batmaci

856

나는 다음을한다 :

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

매번 작동합니다. :)


68
이 글은 SO에서 가장 유용한 글 중 하나입니다.
Jamie Strauss

2
동일한 db를 사용하는 두 개의 레거시 시스템으로 작업했기 때문에이 솔루션을 사용했기 때문에 테이블의 데이터 정렬을 변경하면 기능이 손상되는지 확실하지 않았습니다.
paolobueno

5
동일한 두 필드가 다른 위치 (비교, 조합, 연합 등)에서 함께 사용되는 경우 각 필드에도 데이터 정렬이 지정되어 있는지 확인하십시오.
Zarepheth

5
이것은 매우 유용합니다. 로컬 데이터베이스를 사용하고 연결된 서버에 대해 쿼리하고 있으며 서로 다른 두 데이터 정렬이 있습니다. 분명히 연결된 서버의 데이터 정렬을 변경할 수 없으며 로컬에서 내 데이터를 변경하고 싶지 않으므로 이것이 가장 좋은 대답입니다.
jtate

7
@ppumkin 훌륭한 솔루션이지만 문제를 해결하는 대신 문제를 피할 뿐입니다 . 각 쿼리에 대한 데이터 정렬을 변경하지 않으면 지루하고 최적의 성능을 발휘하지 못합니다. 좋은 답변이지만 내가 받아 들인 대답은 더 좋습니다.
Rob

80

collate쿼리 에서 절을 사용하십시오 .

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

구문이 정확하지 않을 수도 있지만 (BOL 확인) 쿼리의 데이터 정렬을 즉시 변경하려면이 작업을 수행 할 수 있습니다-각 조인에 대한 절을 추가해야 할 수도 있습니다.

편집 : 나는 이것이 옳지 않다는 것을 깨달았습니다-collate 절은 변경 해야하는 필드 뒤에옵니다-이 예에서는 tA.oldValue필드 의 데이터 정렬을 변경했습니다 .


29

이 오류가 발생하는 필드를 식별하고 다음을 추가하십시오. COLLATE DATABASE_DEFAULT

코드 필드에는 두 개의 테이블이 결합되어 있습니다.

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

다음과 같이 쿼리를 업데이트하십시오.

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

감사. prod 데이터베이스에서 작업 할 때 허용되는 답변에서 제안한대로 항상 데이터베이스 구조를 변경할 수는 없습니다.
Jennifer Wood

21

서로 다른 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

@Valkyrie 멋진 답변. 저장 프로 시저 내부의 하위 쿼리를 사용하여 동일한 작업을 수행 할 때 여기에 사례를 넣었습니다.이 경우 귀하의 답변이 효과가 있는지 궁금해했습니다.

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

12

어디에 기준을 추가 collate SQL_Latin1_General_CP1_CI_AS

이것은 나를 위해 작동합니다.

WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS

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 Affiliate ALTER COLUMN myTable NVARCHAR (4000) COLLATE Latin1_General_CI_AS NOT NULL

존재가 필요에 의해 의아해에 나는 인정한다 col.max_length / 2 -


길이는 내부적으로 바이트 수로 저장되기 때문에 2로 나누기가 필요하다고 생각합니다. Nvarchar는 문자 당 1 바이트 대신 2 바이트를 varchar로 사용합니다.
Zebi

- 어떻게 지금까지 위의 쿼리 dosent 수 아마도 때문에 col.max_length / 2의 ncha 데이터 유형에 대한 훌륭한 일
이므 란

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 서버를 시작하십시오.

    net start name_of_instance

  5. 서버의 데이터 정렬을 다시 확인하십시오.

자세한 정보는 다음과 같습니다.

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


2

이것이 DB 전체에서 발생하면 DB 데이터 정렬을 다음과 같이 변경하는 것이 좋습니다.

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

varchar 및 varchar (MAX) 열을 처리하기 위해 @JustSteve의 답변에 코드를 추가했습니다.

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)

2

데이터베이스를 변경하지 않고 쿼리에서이 문제를 해결하려면 "="부호를 사용하여 다른쪽에 표현식을 캐스트 할 수 있습니다.

COLLATE SQL_Latin1_General_CP1_CI_AS

여기에 제안 된대로 .


1

이전 jdbc 드라이버를 사용할 때 비슷한 오류가 발생했습니다 (INTERSECT 작업에서 "SQL_Latin1_General_CP1_CI_AS"와 "SQL_Latin1_General_CP1250_CI_AS"간의 데이터 정렬 충돌을 해결할 수 없음).

Microsoft 또는 오픈 소스 프로젝트 jTDS 에서 새 드라이버를 다운로드하여이 문제를 해결했습니다 .


1

여기에 우리가 한 일이 있습니다.이 상황에서는 요청시 날짜 제한을 사용하여 임시 쿼리를 실행해야하며 쿼리는 테이블에 정의되어 있습니다.

새로운 쿼리는 서로 다른 데이터베이스 간의 데이터를 일치시키고 두 데이터베이스의 데이터를 모두 포함해야합니다.

iSeries / AS400 시스템에서 데이터를 가져 오는 db와보고 데이터베이스간에 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 데이터 도구 / Visual Studio의 SQL Server 스키마 비교를 사용 하여 소스 (새 설치)와 대상 (잘못된 데이터 정렬이있는 DB)을 비교하십시오.

필자의 경우 두 DB를 직접 비교했습니다. 프로젝트를 통해 작업하여 수동으로 조각을 조정할 수 있습니다 ...

  • Visual Studio 실행
  • 새로운 SQL Server 데이터 프로젝트 생성
  • 도구, SQL Server, 새 스키마 비교를 클릭하십시오.
  • 소스 데이터베이스를 선택하십시오
  • 대상 데이터베이스를 선택하십시오
  • 클릭 옵션 (⚙)
    • 아래에서 Object Types관심있는 만 유형을 선택합니다 (나를 위해 만했다 ViewsTables)
    • 아래에서 General선택 :
      • 가능한 데이터 손실을 차단
      • DDL 트리거 비활성화 및 재 활성화
      • 암호화 제공자 파일 경로 무시
      • 파일 및 로그 파일 경로 무시
      • 파일 크기 무시
      • 파일 그룹 배치 무시
      • 전체 텍스트 카탈로그 파일 경로 무시
      • 키워드 대소 문자 무시
      • 로그인 SID 무시
      • 인용 식별자 무시
      • 경로 수명 무시
      • 문장 사이의 세미콜론 무시
      • 공백 무시
      • 스크립트 새로 고침 모듈
      • 새로운 제약 조건에 대한 스크립트 유효성 검사
      • 데이터 정렬 호환성 확인
      • 배포 확인
  • 비교를 클릭하십시오
    • 삭제 플래그가 지정된 객체를 선택 취소합니다 (NB : 데이터 정렬 문제가있을 수 있지만 소스 / 템플릿 DB에 정의되어 있지 않기 때문에 우리는 알지 못합니다. 데이터 정렬 변경 만 타겟팅). DELETE폴더를 마우스 오른쪽 버튼으로 클릭 하고 선택 하여 한 번에 unchceck 할 수 있습니다EXCLUDE .
    • 마찬가지로 제외 CREATE 객체를 하십시오 (여기서는 대상에 존재하지 않기 때문에 잘못된 조합을 가질 수 없습니다. 존재해야하는지 여부는 다른 주제에 대한 질문입니다).
    • 변경 아래의 각 개체를 클릭하면 해당 개체의 스크립트가 표시됩니다. diff를 사용하여 데이터 정렬 만 변경하도록합니다 (다른 차이점은 수동으로 감지 한 경우 해당 개체를 수동으로 제외 / 처리하려는 경우).
  • Update변경 사항을 푸시 하려면 클릭하십시오

여기에는 여전히 수동 작업이 필요하지만 (예 : 데이터 정렬에만 영향을 미치는지 확인) 종속성을 처리합니다.

또한 모든 대상 DB가 동일한 스키마로 가정 할 경우 업데이트 할 데이터베이스가 1 개 이상인 경우 DB에 대한 범용 템플릿을 사용할 수 있도록 유효한 스키마의 데이터베이스 프로젝트를 유지할 수 있습니다.

데이터베이스 프로젝트의 파일에서 찾기 / 바꾸기를 사용하여 설정을 대량으로 수정하려는 경우 (예 : 스키마 비교를 사용하여 유효하지 않은 데이터베이스에서 프로젝트를 생성하고 프로젝트 파일을 수정 한 다음 소스 / 대상을 토글 할 수 있습니다) 스키마를 비교하여 변경 사항을 DB로 다시 푸시하십시오).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.