当字符串包含 space 时 SQL order by 的奇怪行为
Strange behaviour of SQL order by when the string consists space
SQL 示例 1:
SELECT TestField
FROM (VALUES('Ne'), ('NE')) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
结果 1:
Ne
NE
SQL例2(NE和a之间有2个空格,而Ne和a之间只有1个):
SELECT TestField
FROM (VALUES('Ne a'), ('NE a')) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
结果 2:
NE a
Ne a
谁能解释一下?
谢谢
您的第二个样本在值 NE a
中有 两个 spaces - 因此,这将在 之前 [=25] =] Ne a
值只有一个 space(因为(第二个)space 在 a
值之前出现 )。
如果您将第二个值减少为仅包含一个 space,您将获得与 smaple #1 中相同的顺序:
SELECT TestField
FROM (VALUES('Ne a'), ('NE a')) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
输出:
Ne a
NE a
字符串是根据修改后的 ASCII table 通过比较每个字符来排序的。如果第一个字符匹配,则比较下一个字符,依此类推,直到可以确定顺序。 SQL 服务器的 Latin1_General_CS_AS 认为 'E' 和 'e' 是相同的字符,因此它继续移动直到下一个字符差异,即您的 space 和 'a'. space 在 ASCII table 上是 32,而 'a' 被认为是 65(在这种情况下与 'A' 相同)。由于 space (32) 小于 'a' (65),因此 'Ne a' 排在 'NE a' 之前。
第二次查询:
SELECT TestField
FROM (VALUES
('Ne a'),
('NE a')
-- 12345
) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
对于区分大小写的排序规则,按字母顺序产生的差异(位置 4:</code> < <code>a
)比按大小写顺序产生的差异(位置 2:e
< E
)。因此 NE a
在 Ne a
之前。
另一个例子:</code> 和 <code>a
之间的差异(位置 2)比大小写顺序更重要(位置 1:e
vs E
):
SELECT '{' + TestField + '}'
FROM (VALUES
('ea'),
('E ') -- or ('E')
-- 12
) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
/*
TestField
---------
{E }
{ea}
*/
关于 Rusanu blog 的更多详细信息。
更新#1:
您可以使用 SQL_EBCDIC037_CP1_CS_AS
排序规则:
SELECT TestField
FROM (VALUES
('Ne a'),
('NE a')
-- 12345
) AS TestTable(TestField)
ORDER BY TestField COLLATE SQL_EBCDIC037_CP1_CS_AS
/*
TestField
---------
Ne a
NE a
*/
但是这种整理可能会产生一些奇怪的结果。
示例:
SELECT x.ColA AS ColA_Latin1_General_CS_AS
FROM (
SELECT 'A'
UNION ALL
SELECT 'AB'
UNION ALL
SELECT 'ABC'
UNION ALL
SELECT 'zzzz'
) x(ColA)
ORDER BY x.ColA COLLATE Latin1_General_CS_AS
/*
ColA_Latin1_General_CS_AS
----------------------------
A
AB
ABC
zzzz
*/
对比
SELECT x.ColA AS ColA_SQL_EBCDIC037_CP1_CS_AS
FROM (
SELECT 'A'
UNION ALL
SELECT 'AB'
UNION ALL
SELECT 'ABC'
UNION ALL
SELECT 'zzzz'
) x(ColA)
ORDER BY x.ColA COLLATE SQL_EBCDIC037_CP1_CS_AS
/*
ColA_SQL_EBCDIC037_CP1_CS_AS
----------------------------
zzzz
A
AB
ABC
*/
注意:我从未使用过SQL_EBCDIC037_CP1_CS_AS
排序规则,因此我不推荐。
更新 #2: 文本值分为两列(或更多列)
-- Scenario #1: before/during insert/update, spaces are trimmed with LTRIM
SELECT TestField1 F1, TestFiel2 AS F2
FROM (VALUES
('JOHN', 'ZOE'),
('JOHN', 'Albano')
) AS TestTable(TestField1, TestFiel2)
ORDER BY TestField1 COLLATE Latin1_General_CS_AS, TestFiel2 COLLATE Latin1_General_CS_AS
/*
F1 F2
---- ------
JOHN Albano
JOHN ZOE
*/
-- Scenario #2: during insert/update spaces are not trimmed (with LTRIM)
SELECT LTRIM(TestField1) COLLATE Latin1_General_CS_AS AS F1, LTRIM(TestFiel2) COLLATE Latin1_General_CS_AS AS F2
FROM (VALUES
('JOHN', ' ZOE'), -- 1 extra space
('JOHN', 'Albano')
) AS TestTable(TestField1, TestFiel2)
ORDER BY F1, F2
/*
F1 F2
---- ------
JOHN Albano
JOHN ZOE
*/
注意:我会使用 Scenario #1
中描述的解决方案。
SQL 示例 1:
SELECT TestField
FROM (VALUES('Ne'), ('NE')) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
结果 1:
Ne
NE
SQL例2(NE和a之间有2个空格,而Ne和a之间只有1个):
SELECT TestField
FROM (VALUES('Ne a'), ('NE a')) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
结果 2:
NE a
Ne a
谁能解释一下?
谢谢
您的第二个样本在值 NE a
中有 两个 spaces - 因此,这将在 之前 [=25] =] Ne a
值只有一个 space(因为(第二个)space 在 a
值之前出现 )。
如果您将第二个值减少为仅包含一个 space,您将获得与 smaple #1 中相同的顺序:
SELECT TestField
FROM (VALUES('Ne a'), ('NE a')) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
输出:
Ne a
NE a
字符串是根据修改后的 ASCII table 通过比较每个字符来排序的。如果第一个字符匹配,则比较下一个字符,依此类推,直到可以确定顺序。 SQL 服务器的 Latin1_General_CS_AS 认为 'E' 和 'e' 是相同的字符,因此它继续移动直到下一个字符差异,即您的 space 和 'a'. space 在 ASCII table 上是 32,而 'a' 被认为是 65(在这种情况下与 'A' 相同)。由于 space (32) 小于 'a' (65),因此 'Ne a' 排在 'NE a' 之前。
第二次查询:
SELECT TestField
FROM (VALUES
('Ne a'),
('NE a')
-- 12345
) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
对于区分大小写的排序规则,按字母顺序产生的差异(位置 4:</code> < <code>a
)比按大小写顺序产生的差异(位置 2:e
< E
)。因此 NE a
在 Ne a
之前。
另一个例子:</code> 和 <code>a
之间的差异(位置 2)比大小写顺序更重要(位置 1:e
vs E
):
SELECT '{' + TestField + '}'
FROM (VALUES
('ea'),
('E ') -- or ('E')
-- 12
) AS TestTable(TestField)
ORDER BY TestField COLLATE Latin1_General_CS_AS
/*
TestField
---------
{E }
{ea}
*/
关于 Rusanu blog 的更多详细信息。
更新#1:
您可以使用 SQL_EBCDIC037_CP1_CS_AS
排序规则:
SELECT TestField
FROM (VALUES
('Ne a'),
('NE a')
-- 12345
) AS TestTable(TestField)
ORDER BY TestField COLLATE SQL_EBCDIC037_CP1_CS_AS
/*
TestField
---------
Ne a
NE a
*/
但是这种整理可能会产生一些奇怪的结果。
示例:
SELECT x.ColA AS ColA_Latin1_General_CS_AS
FROM (
SELECT 'A'
UNION ALL
SELECT 'AB'
UNION ALL
SELECT 'ABC'
UNION ALL
SELECT 'zzzz'
) x(ColA)
ORDER BY x.ColA COLLATE Latin1_General_CS_AS
/*
ColA_Latin1_General_CS_AS
----------------------------
A
AB
ABC
zzzz
*/
对比
SELECT x.ColA AS ColA_SQL_EBCDIC037_CP1_CS_AS
FROM (
SELECT 'A'
UNION ALL
SELECT 'AB'
UNION ALL
SELECT 'ABC'
UNION ALL
SELECT 'zzzz'
) x(ColA)
ORDER BY x.ColA COLLATE SQL_EBCDIC037_CP1_CS_AS
/*
ColA_SQL_EBCDIC037_CP1_CS_AS
----------------------------
zzzz
A
AB
ABC
*/
注意:我从未使用过SQL_EBCDIC037_CP1_CS_AS
排序规则,因此我不推荐。
更新 #2: 文本值分为两列(或更多列)
-- Scenario #1: before/during insert/update, spaces are trimmed with LTRIM
SELECT TestField1 F1, TestFiel2 AS F2
FROM (VALUES
('JOHN', 'ZOE'),
('JOHN', 'Albano')
) AS TestTable(TestField1, TestFiel2)
ORDER BY TestField1 COLLATE Latin1_General_CS_AS, TestFiel2 COLLATE Latin1_General_CS_AS
/*
F1 F2
---- ------
JOHN Albano
JOHN ZOE
*/
-- Scenario #2: during insert/update spaces are not trimmed (with LTRIM)
SELECT LTRIM(TestField1) COLLATE Latin1_General_CS_AS AS F1, LTRIM(TestFiel2) COLLATE Latin1_General_CS_AS AS F2
FROM (VALUES
('JOHN', ' ZOE'), -- 1 extra space
('JOHN', 'Albano')
) AS TestTable(TestField1, TestFiel2)
ORDER BY F1, F2
/*
F1 F2
---- ------
JOHN Albano
JOHN ZOE
*/
注意:我会使用 Scenario #1
中描述的解决方案。