Làm cách nào để tôi đặt chuỗi Unicode / NVARCHAR của SQL Server thành biểu tượng cảm xúc hoặc ký tự bổ sung?


22

Tôi muốn đặt biến chuỗi Unicode thành ký tự cụ thể dựa trên điểm mã Unicode của nó.

Tôi muốn sử dụng một điểm mã ngoài 65535, nhưng cơ sở dữ liệu SQL Server 2008 R2 có đối chiếu SQL_Latin1_General_CP1_CI_AS.

Theo tài liệu NCHAR của Microsoft , NCHARhàm này có một số nguyên như sau:

số nguyên

Khi đối chiếu cơ sở dữ liệu không chứa cờ ký tự bổ sung (SC), đây là số nguyên dương từ 0 đến 65535 (0 đến 0xFFFF). Nếu một giá trị ngoài phạm vi này được chỉ định, NULL được trả về. Để biết thêm thông tin về các ký tự bổ sung, hãy xem Hỗ trợ đối chiếu và Unicode.

Khi đối chiếu cơ sở dữ liệu hỗ trợ cờ ký tự bổ sung (SC), đây là một số nguyên dương từ 0 đến 1114111 (0 đến 0x10FFFF). Nếu một giá trị ngoài phạm vi này được chỉ định, NULL được trả về.

Mã này:

SELECT NCHAR(128512);

Trả về NULLtrong cơ sở dữ liệu này.

Tôi muốn nó trở lại giống như thế này:

SELECT N'😀';

Làm cách nào tôi có thể đặt biến chuỗi Unicode (ví dụ: nvarchar) thành biểu tượng cảm xúc bằng mã (không sử dụng ký tự biểu tượng cảm xúc thực tế) trong cơ sở dữ liệu trong đó đối chiếu "không chứa cờ ký tự bổ sung (SC)"?

Danh sách đầy đủ các điểm mã biểu tượng cảm xúc Unicode

(Cuối cùng tôi muốn bất kỳ nhân vật nào hoạt động. Tôi chỉ chọn biểu tượng cảm xúc để dễ tham khảo.)

(Mặc dù máy chủ là SQL Server 2008 R2, tôi cũng tò mò về bất kỳ giải pháp nào cho các phiên bản mới hơn.)

Giả sử rằng không có cách nào, tôi có thể tham chiếu một hàm do người dùng nội tuyến xác định trong một cơ sở dữ liệu khác có đối chiếu thích hợp không?

Làm cách nào để tìm một đối chiếu có cờ "ký tự bổ sung"?

Điều này trả về không có hồ sơ trên máy chủ của chúng tôi:

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

Có vẻ như SQL Server 2012 được giới thiệu Latin1_General_100_CI_AS_SCsẽ hoạt động. Bạn có thể cài đặt collations trên các trường hợp cũ hơn?

Tài liệu tham khảo đối chiếu:

Có một lời giải thích cho lý do tại sao, bất kể đối chiếu, SQL Server có thể hiểu và xử lý các ký tự mở rộng ngoại trừ từ quan điểm của NCHAR?


Cảm ơn thông tin bổ sung toàn diện. Tôi không còn phải đối mặt với vấn đề này nữa, nhưng tôi sẽ giữ thông tin này được đánh dấu về mặt tinh thần.
Riley Thiếu tá

1
Không vấn đề gì. Tôi không nghĩ rằng bạn vẫn cần một cái gì đó, chỉ là bạn có thể đánh giá cao / có thể sử dụng sự thích nghi này ...
Solomon Rutzky

Câu trả lời:


35

Mã hóa UCS-2 luôn là 2 byte cho mỗi ký tự và có phạm vi 0 - 65535 (0x0000 - 0xFFFF). UTF-16 (không phân biệt Big Endian hay Little Endian) có phạm vi 0 - 1114111 (0x0000 - 0x10FFFF). Phạm vi 0 - 65535 / 0x0000 - 0xFFFF của UTF-16 là 2 byte mỗi ký tự trong khi phạm vi trên 65536 / 0xFFFF là 4 byte mỗi ký tự.

Windows và SQL Server bắt đầu sử dụng mã hóa UCS-2 vì nó đã có sẵn và UTF-16 chưa được hoàn thiện. Tuy nhiên, may mắn thay, đã có đủ ý tưởng được đưa vào các thiết kế của UCS-2 và UTF-16 rằng các ánh xạ UCS-2 là một tập hợp con hoàn chỉnh của ánh xạ UTF-16 (có nghĩa là: phạm vi 0 - 65535 / 0x0000 - 0xFFFF của UTF-16 UCS-2). VÀ, phạm vi 65536 - 1114111 (0x10000 - 0x10FFFF) của UTF-16 được xây dựng từ hai Điểm Mã trong phạm vi UCS-2 (phạm vi 0xD800 - 0xDBFF và 0xDC00 - 0xDFFF, cụ thể) Ý nghĩa. Sự kết hợp của hai Điểm Mã này được gọi là Cặp thay thế và Cặp thay thế đại diện cho các nhân vật nằm ngoài phạm vi UCS-2 được gọi là Nhân vật bổ sung.

Tất cả thông tin đó giải thích hai khía cạnh của NVARCHAR/ dữ liệu Unicode trong SQL Server:

  1. Một số được xây dựng trong chức năng (không chỉ NCHAR()) không xử lý Surrogate cặp / Nhân vật phụ khi không sử dụng một nhân vật-Aware Collation bổ sung (SCA; một ví dụ với _SC, hoặc _140_ nhưng không phải _BIN*trong tên) vì không SCA Collations (đặc biệt là SQL_Bộ sưu tập) ban đầu được triển khai trước khi UTF-16 được hoàn thành (đôi khi vào năm 2000, tôi tin). Các tổ hợp không SQL__90_hoặc có _100_tên của họ nhưng không _SCcó hỗ trợ tối thiểu cho các Nhân vật bổ sung về mặt so sánh và sắp xếp.
  2. Bộ ký tự Unicode / UTF-16 đầy đủ có thể được lưu trữ, mà không mất dữ liệu, trong NVARCHAR/ NCHAR/ XML/ NTEXTkiểu dữ liệu vì UCS-2 và UTF-16 là các chuỗi byte chính xác giống nhau. Sự khác biệt duy nhất là UTF-16 sử dụng các điểm mã thay thế để xây dựng các cặp thay thế và UCS-2 đơn giản là không thể ánh xạ chúng tới bất kỳ ký tự nào, do đó chúng xuất hiện với các hàm tích hợp dưới dạng hai ký tự không xác định.

Với thông tin cơ bản đó, bây giờ chúng ta có thể đi qua các câu hỏi cụ thể:

Tôi muốn SELECT NCHAR(128512);trả lại giống như thế này:SELECT N'😀';

Điều đó chỉ có thể xảy ra nếu cơ sở dữ liệu hiện tại - nơi truy vấn đang được thực thi - có Collation mặc định là Aware Ký tự bổ sung và được giới thiệu trong SQL Server 2012. Các hàm dựng sẵn có tham số đầu vào chuỗi có thể cung cấp Collation nội tuyến thông qua COLLATEmệnh đề (nghĩa là LEN(N'string' COLLATE Some_Collation_SC)) và không cần phải được thực thi trong Cơ sở dữ liệu có Đối chiếu mặc định SCA. Tuy nhiên, các hàm dựng sẵn như NCHAR()chấp nhận INTtham số đầu vào và COLLATEmệnh đề không hợp lệ trong ngữ cảnh đó (đó là lý do tại sao NCHAR()chỉ hỗ trợ các ký tự bổ sung khi cơ sở dữ liệu hiện tại có đối chiếu mặc định là Aware ký tự bổ sung, nhưng điều này là không cần thiết sự bất tiện có thể thay đổi, vì vậy hãy bỏ phiếu cho đề xuất của tôi:Hàm NCHAR () phải luôn trả về Ký tự bổ sung cho các giá trị 0x10000 - 0x10FFFF bất kể đối chiếu mặc định của cơ sở dữ liệu đang hoạt động ).

Có một lời giải thích cho lý do tại sao, bất kể đối chiếu, SQL Server có thể hiểu và xử lý các ký tự mở rộng ngoại trừ từ quan điểm của NCHAR?

Cách SQL Server có thể lưu trữ và truy xuất các ký tự bổ sung mà không mất dữ liệu đã được giải thích trong phần trên cùng của câu trả lời này. Nhưng, sự thật không phải NCHARlà chức năng tích hợp duy nhất có vấn đề với Nhân vật bổ sung (khi không sử dụng Đối chiếu SCA). Ví dụ: LEN(N'😀' COLLATE SQL_Latin1_General_CP1_CI_AS)trả về giá trị là 2 trong khi LEN(N'😀' COLLATE Latin1_General_100_CI_AS_SC)trả về giá trị là 1.

Nếu bạn truy cập liên kết thứ hai được đăng trong Câu hỏi (tức là "Thông tin đối chiếu các ký tự bổ sung của Microsoft") và cuộn xuống một chút, bạn sẽ thấy một biểu đồ về các chức năng tích hợp và cách chúng hoạt động dựa trên Collation hiệu quả.

Làm cách nào để tìm một đối chiếu có cờ "ký tự bổ sung"?

Trong phiên bản SQL Server trước năm 2012, bạn không thể. Nhưng, bắt đầu với SQL Server 2012, bạn có thể sử dụng truy vấn sau:

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%');

Truy vấn của bạn đã gần, nhưng mẫu bắt đầu bằng SQLvà Bộ sưu tập SQL Server (tức là những bộ bắt đầu bằng SQL_) đã không được dùng trong một thời gian có lợi cho Bộ sưu tập Windows (những bộ không bắt đầu bằng SQL_). Vì vậy, các Bộ SQL_sưu tập không được cập nhật và do đó không có phiên bản mới hơn bao gồm _SCtùy chọn (và bắt đầu trong SQL Server 2017, tất cả các bộ sưu tập mới đều tự động hỗ trợ Ký tự bổ sung và không cần, hoặc có _SCcờ, và có, truy vấn hiển thị ngay trên các tài khoản cho điều đó cũng như chọn các _UTF8đối chiếu được thêm vào trong SQL Server 2019).

Bạn có thể cài đặt collations trên các trường hợp cũ hơn?

Không, bạn không thể cài đặt Collations vào phiên bản SQL Server trước đó.

Làm cách nào tôi có thể đặt biến chuỗi Unicode (ví dụ: nvarchar) thành Ký tự bổ sung bằng cách sử dụng mã (không sử dụng Ký tự bổ sung thực tế) trong cơ sở dữ liệu trong đó đối chiếu "không chứa cờ ký tự bổ sung (SC)"?
...
Mặc dù máy chủ là SQL Server 2008 R2, tôi cũng tò mò về bất kỳ giải pháp nào cho các phiên bản sau.

Khi không sử dụng Đối chiếu SCA, bạn có thể đưa Điểm Mã trên 65535 / U + FFFF theo hai cách:

  1. Chỉ định Cặp thay thế theo hai lệnh gọi đến NCHAR()hàm, mỗi lệnh có một phần của cặp
  2. Chỉ định Cặp thay thế về mặt chuyển đổi VARBINARYhình thức của chuỗi byte Endian (nghĩa là đảo ngược).

Hai phương thức chèn Nhân vật bổ sung / Cặp thay thế này sẽ hoạt động ngay cả khi Đối chiếu hiệu quả là Nhận thức ký tự bổ sung và sẽ hoạt động giống nhau trên tất cả các phiên bản của SQL Server, ít nhất là từ năm 2005 (mặc dù có lẽ cũng sẽ hoạt động trong SQL Server 2000 cũng vậy).

Thí dụ:

  • Tính cách:

                       💩

  • Tên:                Cọc của Poo
  • Số thập phân:            128169
  • Điểm mã:       U + 1F4A9
  • Cặp thay thế: 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)

CẬP NHẬT

Bạn có thể sử dụng iTVF sau để nhận các giá trị Cặp thay thế (cả hai INTBINARYdạng) từ bất kỳ Điểm Mã nào trong khoảng 65536 - 1114111 (0x010000 - 0x10FFFF). Và, trong khi tham số đầu vào là loại INT, bạn có thể chuyển ở dạng nhị phân / hex của Điểm Mã và nó sẽ hoàn toàn chuyển đổi thành giá trị nguyên chính xác.

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

Sử dụng chức năng trên, hai truy vấn sau:

SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);

SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);

cả hai trả về như sau:

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

CẬP NHẬT 2: Một bản cập nhật thậm chí còn tốt hơn!

Tôi đã điều chỉnh iTVF được hiển thị ở trên để trả về 188.657 điểm mã để bạn không cần phải khớp với bất kỳ giá trị cụ thể nào. Tất nhiên, là một TVF, bạn có thể thêm một WHEREmệnh đề để lọc trên một điểm mã cụ thể hoặc phạm vi các điểm mã hoặc "ký tự tương tự", v.v. Và, nó bao gồm các cột bổ sung với các chuỗi thoát được định dạng trước để tạo từng mã điểm (cả BMP và Ký tự bổ sung) theo kiểu T-SQL, HTML và C (nghĩa là \xHHHH). Đọc tất cả về nó ở đây:

Mẹo SSMS # 3: Dễ dàng truy cập / nghiên cứu TẤT CẢ các ký tự Unicode (Có, bao gồm cả biểu tượng cảm xúc)


1
Công việc tuyệt vời của Solomon! Giải thích tuyệt vời
Ronen Ariely
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.