N'Șc 'dianggap kunci duplikat N'C' menggunakan collation Latin1_General_CI_AS


11

Saya punya tabel dengan kunci unik yang menyertakan NVARCHAR(50)kolom (benar atau tidak, tetapi ada di sana). Jadi, ketika mencoba memasukkan Șcatau C(tidak masalah urutan memasukkan) itu rusak pada sisipan ke-2 karena masalah pemeriksaan. Inilah kesalahannya:

(1 baris terpengaruh) Msg 2601, Level 14, Negara 1, Baris 16 Tidak dapat memasukkan baris kunci duplikat di objek 'dbo.testT' dengan indeks unik 'IX_TestT'. Nilai kunci duplikat adalah (C).

Pilih pengembalian:

masukkan deskripsi gambar di sini

Database default collation adalah Latin1_General_CI_AS. Menghabiskan waktu mencari cara untuk menyelesaikannya, tanpa mengubah terlalu banyak struktur yang sudah ada, tetapi tidak dapat menemukan cara untuk mulai bekerja. Mencoba berbagai susunan dan kombinasi, semuanya gagal. Baca (di sini dan di sini ) tentang ekspansi karakter dan sebagainya, masih macet. Berikut adalah contoh kode yang saya gunakan untuk mereplikasi masalah, jangan ragu untuk memodifikasi dan merekomendasikan apa pun yang dapat membantu menyelesaikan masalah ini.

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;

Jawaban:


10

Masalahnya adalah bahwa SQL Server Collations lama (yaitu yang dengan nama dimulai dengan SQL_) dan dua versi pertama dari Windows Collations ( 80seri yang datang dengan SQL Server 2000 dan tidak memiliki nomor versi dalam nama, dan 90seri yang datang dengan SQL Server 2005) hilang semacam bobot untuk banyak karakter. Ini sebagian besar diperbaiki mulai dengan 100seri Collations yang datang dengan SQL Server 2008.

Seperti yang Anda lihat dalam contoh di bawah ini, Șkarakter cocok dengan string kosong ketika menggunakan non-biner, versi 80 atau 90 Collations (dan SQL Server Collations) karena keduanya memiliki bobot jenis yang sama: 0. Tidak ada. Nada. Ini berarti bahwa ketika membandingkan N'Șc'dengan N'C'(menggunakan 100 Collations pra-seri), Anda benar-benar membandingkan N'c'dengan N'C'(tes # 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)

Jadi, sayangnya Anda harus menjatuhkan PK, mengubah kolom untuk memiliki 100 level Collation (misalnya Latin1_General_100_CI_AS_SC), dan kemudian membuat kembali PK. Harap dicatat bahwa perbedaan yang menyarankan Terbit dari Terbit saat ini adalah baik 100 dan yang _SCdi ujung, yang memungkinkan untuk benar menangani karakter tambahan.

Ini tidak berarti bahwa Anda perlu:

  1. ubah susunan tabel lain (kecuali jika mereka memiliki setup yang sama NVARCHARdi PK)
  2. mengubah Collation default Database. Masalah utama dengan tidak mengubah Collation DB adalah bahwa akan ada perbedaan perilaku antara melakukan table.column = N'Ș'dan @variable = N'Ș'karena variabel dan string literal menggunakan Collation default Database.

Untuk lebih banyak contoh perilaku ini, silakan lihat bagian "Karakter Tambahan" dari posting blog saya berikut ini:

The Uni-Code: Pencarian untuk Daftar True Karakter Valid untuk Pengidentifikasi T-SQL, Bagian 3 dari 2 (Pengidentifikasi Terbatas)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.