2017-10-05 65 views
0

問題

當我運行2008 R2,兩個不同的日文Unicode字符串被視爲相等SQL Server上的以下查詢:SQL Server 2008 R2日語錯誤(NVARCHAR)字符串比較?

SELECT 
    CASE 
     WHEN N'食料' = N'食料ㇰ ㇱ ㇲ ㇳ' 
      THEN 1 
     ELSE 0 
    END; 

--result: 1 

我知道假名後的漢字是半角但由於沒有類似的全角假名,所以我不會指望寬度敏感度或假名敏感度。但是,如果假名與全寬版本取代了比較的行爲與預期:

SELECT 
    CASE 
     WHEN N'食料' = N'食料ク シ ス ト' 
      THEN 1 
     ELSE 0 
    END; 

--result: 0 

嘗試的解決方案

這使我認爲這個問題可能與我整理這是SQL_Latin1_General_CP1_CI_AS

首先,我試過Latin1_General_CI_AS以防萬一它是SQL Unicode比較的怪癖,但是這並沒有解決問題。

然後,我想通使用半角尾隨假名時,我會用最嚴格的整理可能(在所有靈敏度),但其它歸類,包括Latin1_General_CS_AS_KS_WSJapanese_Unicode_CS_AS_KS_WS沒有改變的結果(全部正確識別與全寬度之差拖尾假名)。

要驗證字符串在字節級別不同,我在刪除字符串的N(nvarchar)標識並驗證它返回0的預期結果後運行帶有半角尾隨kana的查詢。

問題

這是怎麼回事?我只是沒有嘗試正確的整理?這是SQL Server 2008 R2中的錯誤嗎?有沒有關於日本Unicode的具體內容我不知道?爲什麼半角尾隨假名的出現不會使這些字符串不同?

PS我不知道日語,所以如果我搞砸了我對人物的描述,我很抱歉。

回答

1

它的長短之處在於,在大量的排序規則中,第一個示例中的字符等於空格。

在進行字符串比較時,SQL服務器消除了字符串末尾的尾隨空格(一種例外情況是當您使用LIKE時,但這裏沒有這樣做)。

例如,在字符串N'食料ㇰ ㇱ ㇲ ㇳ'中,之後的每個字符都被視爲尾部空格,並在進行字符串比較時將其刪除。

要做到快速檢查與給定的規則,則可以運行以下查詢:

WITH 
    Vals AS (SELECT FullString, StringNum FROM (VALUES (N'食料', 1), (N'食料ㇰ ㇱ ㇲ ㇳ', 2), (N'食料ク シ ス ト', 3)) AS T(FullString, StringNum)), 
    CTE AS -- A recursive CTE to split the characters up in your strings and check the individual characters. 
    (
     SELECT FullString, 
       StringNum, 
       IndividualCharacter = SUBSTRING(FullString, 1, 1), 
       UnicodeNumber = UNICODE(SUBSTRING(FullString, 1, 1)), 
       UnicodeBinary = CAST(SUBSTRING(FullString, 1, 1) AS VARBINARY(2)), 
       CharPosition = 1 
     FROM Vals 
     UNION ALL 
     SELECT V.FullString, 
       V.StringNum, 
       IndividualCharacter = SUBSTRING(V.FullString, C.CharPosition + 1, 1), 
       UnicodeNumber = UNICODE(SUBSTRING(V.FullString, C.CharPosition + 1, 1)), 
       UnicodeBinary = CAST(SUBSTRING(V.FullString, C.CharPosition + 1, 1) AS VARBINARY(2)), 
       CharPosition = C.CharPosition + 1 
     FROM Vals AS V 
     JOIN CTE AS C 
      ON C.StringNum = V.StringNum 
     WHERE C.CharPosition + 1 <= LEN(V.FullString) 
    ) 
SELECT C.*, 
     CharacterEqualToSpace = CASE WHEN NCHAR(C.UnicodeNumber) COLLATE Japanese_Unicode_CS_AS_KS_WS = NCHAR(32) THEN 1 ELSE 0 END, 
     FullStringWithoutSpace = SUBSTRING(C.FullString, 1, (SELECT MAX(CharPosition) FROM CTE AS C2 WHERE C2.StringNum = C.StringNum AND NCHAR(C2.UnicodeNumber) COLLATE Japanese_Unicode_CS_AS_KS_WS != NCHAR(32))) -- Eliminate white space on the end for this collation, with a substring ending at the last character that does not equal white space. 
FROM CTE AS C 
ORDER BY StringNum, CharPosition; 

從做一些快速測試... - 日本的排序規則是不會治療那些特定的字符作爲一個空格:任何BIN整理,Japanese_Bushu_Kakusu,Japanese_XJIS - 日本的排序規則是治療那些特定的字符作爲一個空格:日本,Japanese90,Japanese_Unicode

注:在Japanese_Unicode_CS_AS_KS_WS中有超過21000個字符被視爲空白。您可以通過針對給定整理運行如下查詢來檢查此問題:

WITH T(N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) AS A(B)), -- 16 
    T2(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 FROM T AS A CROSS JOIN T AS B CROSS JOIN T AS C CROSS JOIN T) -- 16^4. 
SELECT WhiteSpaceCharacters = NCHAR(N) 
FROM T2 
WHERE NCHAR(N) COLLATE Japanese_Unicode_CS_AS_KS_WS = NCHAR(32);