今天在使用SQL时,我们发现SQL并没有像我们期望的那样对字符串进行排序。
这是我们的数据集列表:(URL缩短了以防止滥用)
http://10.10.14
http://192.168.
https://m.hanno
https://online.
https://online-
https://owi-000
https://owi2.su
https://owi2-00
https://owi2-71
https://owi-700
https://owi-702
https://owi-703
https://owi-704
https://owi-707
https://owi-708
https://owi-710
https://owi-711
https://owi-712
https://owi-713
https://owi-714
https://owi-715
https://owi-716
https://owi-717
https://owigo.n
https://owigosm
https://owigow.
owi2-URL直接位于owi-000之后。但是,它应该在owi-717之后或owi-000之前,但绝对不能在它们之间。
...
https://owi-000
https://owi2.su
https://owi2-00
https://owi2-71
https://owi-700
...
这就是我们期望的结果。减号在ASCII和许多其他字符编码的2之前。因此,所有带有owi2的网址都应在owi-之后。
...
https://owi-717
https://owi2.su
https://owi2-00
https://owi2-71
https://owigo.n
...
我们在MS Excel中复制了所有URL,令人惊讶的是我们得到了相同的结果。因此,我们检查了字符串以确保没有非打印字符引起该问题。实际上,我们发现没有使用Notepad ++的非打印字符。
我们的问题是:为什么SQL以这种方式对URL进行排序?
答案 0 :(得分:4)
TLDR :
确保您具有VARCHAR而不是NVARCHAR。 NVARCHAR字符串将忽略连字符。如果您无法更改数据类型,请尝试使用排序规则Latin1_General_CI_AS
就像之前在here和SO here上here这样的地方所提到的,连字符在字母数字字符排序中的使用方式有所不同。
典型归类在排序时会忽略连字符。 引用MSDN文章:
用于排序非Unicode数据的SQL归类规则不兼容 与Microsoft Windows提供的任何排序例程 操作系统;但是,Unicode数据的排序是兼容的 使用特定版本的Windows排序规则。因为 当非Unicode和Unicode数据的比较规则不同时, 您使用SQL排序规则时,您可能会看到不同的结果 相同字符的比较,取决于基础数据 类型。例如,如果您使用的是SQL排序规则 “ SQL_Latin1_General_CP1_CI_AS”,非Unicode字符串'a-c'较少 比字符串“ ab”要多,因为连字符(“-”)被单独排序 “ b”之前的字符。但是,如果您转换这些字符串 到Unicode,然后执行相同的比较,即Unicode字符串 N'a-c'被认为大于N'ab',因为Unicode 排序规则使用忽略连字符的“单词排序”。
答案 1 :(得分:1)
或者,如果您确实需要使用nvarchar
,则可以使用其他排序规则。您可以更改表中列的排序规则,但这可能会产生不希望的影响,因为如果比较不匹配,则您需要对它们进行任何比较。这将影响可保存性。考虑到您只想订购该产品,则可以简单地使用COLLATE
关键字。例如:
SELECT ROW_NUMBER() OVER (ORDER BY URL COLLATE SQL_Latin1_General_CP1_CI_AS),
ROW_NUMBER() OVER (ORDER BY CONVERT(nvarchar(20),URL) COLLATE SQL_Latin1_General_CP1_CI_AS),
ROW_NUMBER() OVER (ORDER BY URL COLLATE Latin1_General_CI_AS),
ROW_NUMBER() OVER (ORDER BY CONVERT(nvarchar(20),URL) COLLATE Latin1_General_CI_AS),
ROW_NUMBER() OVER (ORDER BY URL COLLATE Latin1_General_100_BIN2),
ROW_NUMBER() OVER (ORDER BY CONVERT(nvarchar(20),URL) COLLATE Latin1_General_100_BIN2),
URL
FROM (VALUES('http://10.10.14'),
('http://192.168.'),
('https://m.hanno'),
('https://online.'),
('https://online-'),
('https://owi-000'),
('https://owi2.su'),
('https://owi2-00'),
('https://owi2-71'),
('https://owi-700'),
('https://owi-702'),
('https://owi-703'),
('https://owi-704'),
('https://owi-707'),
('https://owi-708'),
('https://owi-710'),
('https://owi-711'),
('https://owi-712'),
('https://owi-713'),
('https://owi-714'),
('https://owi-715'),
('https://owi-716'),
('https://owi-717'),
('https://owigo.n'),
('https://owigosm'),
('https://owigow.'))V(URL)
ORDER BY URL COLLATE Latin1_General_CI_AS;
在这里您可以看到排序规则SQL_Latin1_General_CP1_CI_AS
对于varchar
到nvarchar
具有不同的顺序。另一方面,Latin1_General_CI_AS
对于这两者都是一致的(复制nvarchar
与排序规则SQL_Latin1_General_CP1_CI_AS
的顺序)。 Latin1_General_100_BIN2
也是一致的,但对varchar
遵循相同的顺序。