当我在SQL Server 2008 R2上运行以下查询时,两个不同的日语unicode字符串被视为相等:
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_WS
和Japanese_Unicode_CS_AS_KS_WS
在使用半宽尾随假名时没有改变结果(所有正确确定了与全宽尾随假名的差异。)
要验证字符串级别的字符串是否不同,我在删除字符串的N
(nvarchar)指定后运行半宽跟踪假名查询并验证它返回{{的预期结果1}}。
这里发生了什么?我只是不尝试正确的整理?这是SQL Server 2008 R2中的错误吗?我不知道有关于日语Unicode的具体内容吗?为什么半宽尾随假名的存在不会使这些字符串不同?
PS我不懂日语,所以如果我搞砸了我道歉的人物描述。
答案 0 :(得分:1)
它的长短在于,在大量的排序规则中,第一个例子中的字符等于空格。
在进行字符串比较时,SQL Server会删除字符串末尾的尾随空格(当您使用var isProductionEnv = process.env.NODE_ENV === 'production';
app.use([
cookieParser(process.env.SESSION_SECRET),
session({
resave: false,
saveUninitialized: true,
secret: process.env.SESSION_SECRET,
store: new MongoStore({ url: MONGO_URL, autoReconnect: true }),
proxy: isProductionEnv,
cookie: {
secure:isPrudictionEnv,
},
}), lusca({
csrf: true,
xframe: 'SAMEORIGIN',
xssProtection: true,
})]);
app.set('trust proxy', isProductionEnv);
时会有一个例外,但您在此处没有这样做)。
因此,例如,在字符串LIKE
中,N'食料ㇰ ㇱ ㇲ ㇳ'
之后的每个字符都被视为尾随空格,并在进行字符串比较时被删除。
要使用给定的排序规则进行快速检查,您可以运行以下查询:
料
做一些快速测试...... - 不会将这些特定字符视为空格的日语归类:任何BIN归类,Japanese_Bushu_Kakusu,Japanese_XJIS - 日语归类 将这些特定字符视为空格:日语,日语90,日语_Unicode
注意:Japanese_Unicode_CS_AS_KS_WS中有超过21000个字符被视为空格。您可以通过针对给定的排序规则运行以下查询来检查此问题:
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;