N'Șc 'พิจารณาคีย์ที่ซ้ำกันของ N'C' โดยใช้การเปรียบเทียบ Latin1_General_CI_AS


11

ฉันมีตารางที่มีคีย์เฉพาะที่มีNVARCHAR(50)คอลัมน์ (ถูกต้องหรือไม่ แต่มีอยู่) ดังนั้นเมื่อพยายามที่จะแทรกȘcหรือC(ไม่สำคัญกับคำสั่งของเม็ดมีด) มันจะแตกบนเม็ดที่สองเนื่องจากปัญหาการเรียง นี่คือข้อผิดพลาด:

(รับผลกระทบ 1 แถว) ข่าวสารเกี่ยวกับ 2601, ระดับ 14, สถานะ 1, บรรทัดที่ 16 ไม่สามารถแทรกแถวคีย์ซ้ำในวัตถุ 'dbo.testT' ด้วยดัชนีเฉพาะ 'IX_TestT' ค่าคีย์ที่ซ้ำกันคือ (C)

เลือกผลตอบแทน:

ป้อนคำอธิบายรูปภาพที่นี่

Latin1_General_CI_ASเปรียบเทียบค่าเริ่มต้นฐานข้อมูลเป็น ใช้เวลาดูวิธีการแก้ปัญหาโดยไม่ต้องเปลี่ยนโครงสร้างที่มีอยู่แล้ว แต่ไม่สามารถหาวิธีทำงานได้ พยายามเรียงความและรวมที่แตกต่างกันทุกอย่างล้มเหลว อ่าน ( ที่นี่และที่นี่ ) เกี่ยวกับการขยายตัวอักขระและอื่น ๆ ยังคงติดอยู่ นี่คือตัวอย่างรหัสที่ฉันใช้เพื่อทำซ้ำปัญหารู้สึกฟรีเพื่อแก้ไขและแนะนำสิ่งที่สามารถช่วยแก้ปัญหานี้ได้

CREATE TABLE testT (
    [Default_Collation]     [NVARCHAR] (50) COLLATE DATABASE_DEFAULT,
    [Latin1_General_CI_AS]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AS,
    [Latin1_General_CI_AI]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AI,
    [SQL_Collation]         [NVARCHAR] (50) COLLATE SQL_Latin1_General_CP1_CI_AS);
CREATE UNIQUE CLUSTERED INDEX [IX_TestT] ON [dbo].[testT] ([Default_Collation])
ON [PRIMARY]
GO

INSERT INTO testT
SELECT  N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc'   --COLLATE Latin1_General_CI_AS

INSERT INTO testT
SELECT  N'C'    --COLLATE Latin1_General_CI_AS 
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE SQL_Latin1_General_CP1_CI_AS

SELECT * FROM testT;

DROP TABLE testT;

คำตอบ:


10

ปัญหาคือ SQL Server Collations เก่า (เช่นชื่อที่ขึ้นต้นด้วยSQL_) และ Windows Collations รุ่นที่สอง ( 80ชุดที่มาพร้อมกับ SQL Server 2000 และไม่มีหมายเลขรุ่นในชื่อและ90ชุดที่ มาพร้อมกับ SQL Server 2005) ขาดน้ำหนักการจัดเรียงสำหรับตัวละครมากมาย สิ่งนี้ได้รับการแก้ไขเป็นส่วนใหญ่เริ่มต้นด้วยการ100เรียงชุดข้อมูลที่มาพร้อมกับ SQL Server 2008

ดังที่คุณเห็นในตัวอย่างด้านล่างȘอักขระตรงกับสตริงว่างเมื่อใช้การไม่ใช่แบบไบนารีรุ่น 80 หรือ 90 Collation (และ SQL Server Collations) เนื่องจากทั้งคู่มีน้ำหนักเรียงเหมือนกัน: 0. ไม่มีเลย Nada ซึ่งหมายความว่าเมื่อเปรียบเทียบN'Șc'กับN'C'(ใช้การเปรียบเทียบ 100 ชุดก่อนหน้า) คุณกำลังเปรียบเทียบN'c'กับN'C'(ทดสอบ # 1) จริง ๆ :

SELECT 1 WHERE N'Șc' = N'C' COLLATE Latin1_General_CS_AS;
-- no result (due to "c" and "C" being different case)

SELECT 2 WHERE N'Ș' = N'' COLLATE SQL_Latin1_General_CP1_CI_AS;
SELECT 3 WHERE N'Ș' = N'' COLLATE Latin1_General_CI_AS;

SELECT 4 WHERE N'Ș' = N'' COLLATE Latin1_General_BIN2;
-- no result (due to "Ș" still being a code point and empty string has no code points)

SELECT 5 WHERE N'Ș' = N'' COLLATE Latin1_General_100_CI_AS;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

SELECT 6 WHERE N'Ș' = N'' COLLATE Chinese_PRC_CI_AI;
SELECT 7 WHERE N'Ș' = N'' COLLATE Chinese_PRC_90_CI_AI;

SELECT 8 WHERE N'Ș' = N'' COLLATE Indic_General_90_CI_AI;
SELECT 9 WHERE N'Ș' = N'' COLLATE Indic_General_100_CI_AI;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

ดังนั้นน่าเสียดายที่คุณจะต้องวาง PK เปลี่ยนคอลัมน์เพื่อให้มีการจัดเรียง 100 ระดับ (เช่นLatin1_General_100_CI_AS_SC) แล้วสร้าง PK อีกครั้ง โปรดทราบว่าแตกต่างกันในการที่แนะนำการเปรียบเทียบจากการเปรียบเทียบในปัจจุบันเป็นทั้ง100 และ_SCที่สิ้นสุดซึ่งช่วยให้สามารถจัดการกับตัวละครเสริม

นี่ไม่ได้หมายความว่าคุณต้อง:

  1. เปลี่ยน Collation ของตารางอื่น ๆ (เว้นแต่ว่าพวกเขามีการตั้งค่าเดียวกันNVARCHARใน PK)
  2. เปลี่ยน Collation เริ่มต้นของฐานข้อมูล ปัญหาหลักที่ไม่มีการเปลี่ยนแปลงการเปรียบเทียบของฐานข้อมูลคือจะมีความแตกต่างของพฤติกรรมระหว่างการทำtable.column = N'Ș'และ@variable = N'Ș'เนื่องจากตัวแปรและตัวอักษรสตริงใช้การจัดเรียงเริ่มต้นของฐานข้อมูล

สำหรับตัวอย่างเพิ่มเติมของพฤติกรรมนี้โปรดดูที่ส่วน "อักขระเพิ่มเติม" ของโพสต์บล็อกของฉันต่อไปนี้:

The Uni-Code: การค้นหารายชื่อตัวละครที่ถูกต้องสำหรับตัวระบุ T-SQL, ส่วนที่ 3 จาก 2 (ตัวระบุที่มีตัวคั่น)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.