Bagaimana cara menetapkan string SQL Server Unicode / NVARCHAR ke emoji atau Karakter Tambahan?

23

Saya ingin mengatur variabel string Unicode ke karakter tertentu berdasarkan titik kode Unicode-nya.

Saya ingin menggunakan titik kode di luar 65535, tetapi database SQL Server 2008 R2 memiliki susunan SQL_Latin1_General_CP1_CI_AS.

Menurut dokumentasi NCHAR Microsoft , NCHARfungsi tersebut mengambil bilangan bulat sebagai berikut:

integer_expression

Ketika susunan basis data tidak mengandung bendera karakter tambahan (SC), ini adalah bilangan bulat positif dari 0 hingga 65535 (0 hingga 0xFFFF). Jika nilai di luar rentang ini ditentukan, NULL dikembalikan. Untuk informasi lebih lanjut tentang karakter tambahan, lihat Dukungan Collation dan Unicode.

Ketika pengumpulan database mendukung bendera karakter tambahan (SC), ini adalah bilangan bulat positif dari 0 hingga 1114111 (0 hingga 0x10FFFF). Jika nilai di luar rentang ini ditentukan, NULL dikembalikan.

Jadi kode ini:

SELECT NCHAR(128512);

Kembali NULLdalam database ini.

Saya ingin mengembalikan yang sama seperti ini:

SELECT N'😀';

Bagaimana saya bisa mengatur variabel string Unicode (misalnya nvarchar) ke emoji menggunakan kode (tanpa menggunakan karakter emoji yang sebenarnya) dalam database di mana collation "tidak mengandung flag karakter tambahan (SC)"?

Daftar lengkap poin kode emoji Unicode

(Pada akhirnya saya ingin karakter apa pun bekerja. Saya hanya memilih emoji untuk kemudahan referensi.)

(Meskipun servernya SQL Server 2008 R2, saya juga ingin tahu tentang solusi apa pun untuk versi yang lebih baru.)

Dengan asumsi bahwa tidak ada cara, dapatkah saya mereferensikan fungsi inline yang didefinisikan pengguna dalam database lain yang memiliki susunan yang sesuai?

Bagaimana cara menemukan collation yang memiliki bendera "karakter tambahan"?

Ini tidak mengembalikan catatan di server kami:

SELECT * FROM sys.fn_helpcollations() 
WHERE name LIKE 'SQL%[_]SC';

Sepertinya SQL Server 2012 diperkenalkan Latin1_General_100_CI_AS_SCyang akan bekerja. Bisakah Anda menginstal collations pada instances lama?

Referensi Penyusunan:

Apakah ada penjelasan mengapa, terlepas dari pemeriksaan, SQL Server dapat memahami dan menangani karakter yang diperluas kecuali dari perspektif NCHAR?

Riley Major
sumber
Terima kasih atas informasi tambahan yang komprehensif. Saya tidak lagi menghadapi masalah ini, tetapi saya akan menyimpan informasi ini secara mental.
Riley Major
1
Tidak masalah. Saya tidak berpikir Anda masih membutuhkan sesuatu, hanya saja Anda mungkin menghargai / dapat memanfaatkan adaptasi ...
Solomon Rutzky

Jawaban:

36

Pengkodean UCS-2 selalu 2 byte per karakter dan memiliki kisaran 0 - 65535 (0x0000 - 0xFFFF). UTF-16 (terlepas dari Big Endian atau Little Endian) memiliki kisaran 0 - 1114111 (0x0000 - 0x10FFFF). Rentang 0 - 65535 / 0x0000 - 0xFFFF dari UTF-16 adalah 2 byte per karakter sedangkan kisaran di atas 65536 / 0xFFFF adalah 4 byte per karakter.

Windows dan SQL Server mulai menggunakan pengkodean UCS-2 karena sudah tersedia dan UTF-16 belum selesai. Untungnya, bagaimanapun, ada cukup pemikiran ke depan dimasukkan ke dalam desain UCS-2 dan UTF-16 bahwa pemetaan UCS-2 adalah bagian lengkap dari pemetaan UTF-16 (artinya: kisaran 0 - 65535 / 0x0000 - 0xFFFF UTF-16 adalah UCS-2). DAN, kisaran UTF-16 65536 - 1114111 (0x10000 - 0x10FFFF) dibangun dari dua Poin Kode dalam kisaran UCS-2 (kisaran 0xD800 - 0xDBFF dan 0xDC00 - 0xDFFF, khusus) yang disediakan untuk tujuan ini dan sebaliknya tidak memiliki berarti. Kombinasi dua Poin Kode ini dikenal sebagai Pasangan Pengganti, dan Pasangan Pengganti mewakili karakter di luar rentang UCS-2 yang dikenal sebagai Karakter Tambahan.

Semua informasi itu menjelaskan dua aspek NVARCHAR/ data Unicode di SQL Server:

  1. Beberapa fungsi bawaan (tidak hanya NCHAR()) tidak menangani Pasangan Pengganti / Karakter Tambahan saat tidak menggunakan Collation Character-Aware Collation (SCA; yaitu satu dengan _SC, atau _140_ tetapi tidak _BIN*dalam nama) karena Collations non-SCA (terutama SQL_Collations) awalnya dilaksanakan sebelum UTF-16 selesai (sekitar tahun 2000, saya percaya). Non- SQL_Collations yang memiliki _90_atau _100_atas nama mereka tetapi tidak _SCmemiliki dukungan minimal untuk Karakter Tambahan dalam hal perbandingan dan penyortiran.
  2. Penuh Unicode / UTF-16 set karakter dapat disimpan, tanpa kehilangan data, dalam NVARCHAR/ NCHAR/ XML/ NTEXTtipe data karena UCS-2 dan UTF-16 adalah urutan byte yang sama persis. Satu-satunya perbedaan adalah bahwa UTF-16 memanfaatkan titik kode pengganti untuk membangun Pasangan Pengganti, dan UCS-2 tidak dapat memetakannya ke karakter apa pun, oleh karena itu mereka muncul pada fungsi bawaan sebagai dua karakter yang tidak dikenal.

Dengan mengingat informasi latar belakang itu, sekarang kita dapat melalui pertanyaan spesifik:

Saya ingin SELECT NCHAR(128512);mengembalikan yang sama seperti ini:SELECT N'😀';

Itu hanya dapat terjadi jika database saat ini - di mana kueri sedang dieksekusi - memiliki Collation default yang Tambahan Karakter-Sadar, dan yang diperkenalkan di SQL Server 2012. Fungsi bawaan yang memiliki parameter input string dapat memiliki Collation yang disediakan sebaris melalui COLLATEklausa (yaitu LEN(N'string' COLLATE Some_Collation_SC)) dan tidak perlu dijalankan dalam Database yang memiliki Collation default SCA. Namun, fungsi bawaan seperti NCHAR()menerima INTparameter input dan COLLATEklausa tidak valid dalam konteks itu (itulah sebabnya NCHAR()hanya mendukung Karakter Tambahan ketika database saat ini memiliki susunan default yang Sadar Karakter-Sadar; tetapi ini tidak perlu ketidaknyamanan yang dapat diubah, jadi silakan pilih saran saya:Fungsi NCHAR () harus selalu mengembalikan Karakter Tambahan untuk nilai 0x10000 - 0x10FFFF terlepas dari susunan default basis data aktif ).

Apakah ada penjelasan mengapa, terlepas dari pemeriksaan, SQL Server dapat memahami dan menangani karakter yang diperluas kecuali dari perspektif NCHAR?

Bagaimana SQL Server dapat menyimpan dan mengambil karakter tambahan tanpa kehilangan data dijelaskan di bagian atas jawaban ini. Tetapi, tidak benar bahwa NCHARsatu-satunya fungsi bawaan yang memiliki masalah dengan Karakter Tambahan (saat tidak menggunakan SCA Collation). Misalnya, LEN(N'😀' COLLATE SQL_Latin1_General_CP1_CI_AS)mengembalikan nilai 2 sementara LEN(N'😀' COLLATE Latin1_General_100_CI_AS_SC)mengembalikan nilai 1.

Jika Anda pergi ke tautan kedua yang diposting di Pertanyaan (yaitu "Informasi Pengumpulan Karakter Tambahan Microsoft") dan gulirkan sedikit ke bawah, Anda akan melihat bagan fungsi bawaan dan bagaimana mereka berperilaku berdasarkan Kolasi efektif.

Bagaimana cara menemukan collation yang memiliki bendera "karakter tambahan"?

Dalam versi SQL Server sebelum 2012 Anda tidak bisa. Tetapi, dimulai dengan SQL Server 2012, Anda dapat menggunakan kueri berikut:

SELECT col.*
FROM   sys.fn_helpcollations() col
WHERE  col.[name] LIKE N'%[_]SC'
OR     col.[name] LIKE N'%[_]SC[_]%'
OR     (COLLATIONPROPERTY(col.[name], 'Version') = 3
      AND col.[name] NOT LIKE N'%[_]BIN%');

Permintaan Anda sudah dekat, tetapi pola dimulai dengan SQLdan SQL Server Collations (yaitu yang dimulai dengan SQL_) telah ditinggalkan untuk sementara waktu karena Windows Collations (yang tidak dimulai dengan SQL_). Jadi, SQL_Collations tidak diperbarui dan karenanya tidak memiliki versi yang lebih baru yang akan menyertakan _SCopsi (dan mulai di SQL Server 2017, semua collations baru secara otomatis mendukung Karakter Tambahan dan tidak perlu, atau memiliki, _SCbendera; dan ya, kueri ditampilkan segera di atas akun untuk itu serta mengambil _UTF8collations yang ditambahkan di SQL Server 2019).

Bisakah Anda menginstal collations pada instances lama?

Tidak, Anda tidak dapat menginstal Collations ke versi SQL Server sebelumnya.

Bagaimana saya bisa mengatur variabel string Unicode (misalnya nvarchar) ke Karakter Tambahan menggunakan kode (tanpa menggunakan Karakter Tambahan yang sebenarnya) dalam database di mana collation "tidak mengandung flag karakter tambahan (SC)"?
...
Meskipun servernya adalah SQL Server 2008 R2, saya juga ingin tahu tentang solusi apa pun untuk versi yang lebih baru.

Saat tidak menggunakan Collation SCA, Anda bisa menyuntikkan Poin Kode di atas 65535 / U + FFFF dengan dua cara:

  1. Tentukan Pasangan Pengganti dalam hal dua panggilan ke NCHAR()fungsi, masing-masing dengan satu bagian dari pasangan
  2. Tentukan Pasangan Pengganti dalam hal mengkonversi VARBINARYbentuk urutan byte Little Endian (yaitu dibalik).

Dua metode ini memasukkan Karakter Tambahan / Pasangan Pengganti akan bekerja bahkan jika Kolasi yang efektif adalah Karakter Tambahan-Sadar, dan harus bekerja sama di semua versi SQL Server, setidaknya sejauh 2005 (walaupun mungkin juga akan bekerja di SQL Server 2000 juga).

Contoh:

  • Karakter:

                       💩

  • Nama:                Tumpukan Poo
  • Desimal:            128169
  • Poin Kode:       U + 1F4A9
  • Pasangan Pengganti: U + D83D & U + DF21
SELECT N'💩', -- 💩
       UNICODE(N'💩' COLLATE Latin1_General_100_CI_AS), -- 55357
       UNICODE(N'💩' COLLATE Latin1_General_100_CI_AS_SC), -- 128169
       NCHAR(128169), -- 💩 in DB with _SC Collation, else NULL
       NCHAR(0x1F4A9), -- 💩 in DB with _SC Collation, else NULL
       CONVERT(VARBINARY(4), 128169), -- 0x0001F4A9
       CONVERT(VARBINARY(4), N'💩'), -- 0x3DD8A9DC
       CONVERT(NVARCHAR(10), 0x3DD8A9DC), -- 💩 (regardless of DB Collation)
       NCHAR(0xD83D) + NCHAR(0xDCA9) -- 💩 (regardless of DB Collation)

MEMPERBARUI

Anda dapat menggunakan iTVF berikut untuk mendapatkan nilai Pasangan Pengganti (dalam keduanya INTdan dalam BINARYbentuk) dari Titik Kode mana saja antara 65536 - 1114111 (0x010000 - 0x10FFFF). Dan, sementara parameter input bertipe INT, Anda bisa meneruskan dalam bentuk biner / hex dari Kode Point dan secara implisit akan dikonversi ke nilai integer yang benar.

CREATE FUNCTION dbo.GetSupplementaryCharacterInfo(@CodePoint INT)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN

WITH calc AS
(
  SELECT 55232 + (@CodePoint / 1024) AS [HighSurrogateINT],
         56320 + (@CodePoint % 1024) AS [LowSurrogateINT]
  WHERE  @CodePoint BETWEEN  65536 AND 1114111
)
SELECT @CodePoint AS [CodePointINT],
       HighSurrogateINT,
       LowSurrogateINT,
       CONVERT(VARBINARY(3), @CodePoint) AS [CodePointBIN],
       CONVERT(BINARY(2), HighSurrogateINT) AS [HighSurrogateBIN],
       CONVERT(BINARY(2), LowSurrogateINT) AS [LowSurrogateBIN],
       CONVERT(binary(4), NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT)) AS [UTF-16LE],
       NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT) AS [Character]
FROM   calc;
GO

Menggunakan fungsi di atas, dua pertanyaan berikut:

SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);

SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);

keduanya mengembalikan yang berikut:

CodePoint  HighSurrogate  LowSurrgate  CodePoint  HighSurrgate  LowSurrgate  UTF-16LE   Char
INT        INT            INT          BIN        BIN           BIN                     actr
128169     55357          56489        0x01F4A9   0xD83D        0xDCA9       0x3DD8A9DC   💩

UPDATE 2: Pembaruan Yang Lebih Baik!

Saya telah mengadaptasi iTVF yang ditunjukkan di atas untuk sekarang mengembalikan 188.657 poin kode sehingga Anda tidak perlu mencocokkannya dengan nilai tertentu. Tentu saja, sebagai TVF, Anda dapat menambahkan WHEREklausa untuk memfilter pada titik kode tertentu, atau rentang titik kode, atau "karakter serupa", dll. Dan, itu termasuk kolom tambahan dengan urutan pelarian yang telah diformat untuk membangun setiap kode point (baik BMP dan Karakter Tambahan) dalam T-SQL, HTML, dan C-style (yaitu \xHHHH). Baca semua tentang ini di sini:

Tip SSMS # 3: Mudah Mengakses / Meneliti SEMUA Karakter Unicode (Ya, Termasuk Emoji 😸)

Solomon Rutzky
sumber
1
Kerja bagus Solomon! Penjelasan luar biasa
Ronen Ariely