SQL 字母数字排序问题
SQL Alpha Numeric sorting issue
我发现我们可以对 table 中的列进行排序,即使它是字母数字。
这里我遇到的唯一问题是,如果列数据只是字符,它会抛出错误。
BEGIN TRAN
USE SomeDatabase
CREATE TABLE dbo.Section
(
Section varchar(50) NULL
)
INSERT INTO dbo.Section (Section.Section) VALUES ('BB')
INSERT INTO dbo.Section (Section.Section) VALUES ('1 ')
INSERT INTO dbo.Section (Section.Section) VALUES ('AB 1')
INSERT INTO dbo.Section (Section.Section) VALUES ('A21')
INSERT INTO dbo.Section (Section.Section) VALUES ('B2')
INSERT INTO dbo.Section (Section.Section) VALUES ('A11')
INSERT INTO dbo.Section (Section.Section) VALUES ('B20')
INSERT INTO dbo.Section (Section.Section) VALUES ('B21')
INSERT INTO dbo.Section (Section.Section) VALUES ('AB10')
INSERT INTO dbo.Section (Section.Section) VALUES ('A10')
SELECT Section
FROM dbo.Section
SELECT Section
FROM dbo.Section
ORDER BY LEFT(Section,PATINDEX('%[0-9]%',Section)-1), -- alphabetical sort
CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) -- numerical sort
DROP Table dbo.Section
ROLLBACK
所以,排序 'BB' 就是问题所在。如果你删除 BB 那么一切正常。
从您的代码来看,一个明显的问题是 PATINDEX
如果没有找到任何东西,它将 return 0。因为您随后将 0 - 1
作为长度,所以 LEFT 函数将抛出错误。
试试这个:
...
ORDER BY LEFT(Section
,CASE WHEN PATINDEX('%[0-9]%',Section) >= 2
THEN PATINDEX('%[0-9]%',Section) - 1
ELSE LEN(Section)
END
), -- alphabetical sort
CASE WHEN PATINDEX('%[0-9]%',Section) >= 1
THEN CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section) - PATINDEX('%[0-9]%',Section) - 1))
END -- numerical sort
...
问题是 Patindex 在两个 order by 子句中都返回 0。我在下面更正了。
declare @Section TABLE
(
Section varchar(50) NULL
)
INSERT INTO @Section (Section) VALUES ('BB')
INSERT INTO @Section (Section) VALUES ('1 ')
INSERT INTO @Section (Section) VALUES ('AB 1')
INSERT INTO @Section (Section) VALUES ('A21')
INSERT INTO @Section (Section) VALUES ('B2')
INSERT INTO @Section (Section) VALUES ('A11')
INSERT INTO @Section (Section) VALUES ('B20')
INSERT INTO @Section (Section) VALUES ('B21')
INSERT INTO @Section (Section) VALUES ('AB10')
INSERT INTO @Section (Section) VALUES ('A10')
SELECT Section
FROM @Section
SELECT Section
FROM @Section
ORDER BY Section
--LEFT(Section,PATINDEX('%[0-9]%',Section)-1), -- alphabetical sort
-- CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) -- numerical sort
SELECT Section
FROM @Section
ORDER BY LEFT(Section,case when PATINDEX('%[0-9]%',Section) < 1 then 1 else PATINDEX('%[0-9]%',Section) end -1), -- alphabetical sort
case when PATINDEX('%[0-9]%',Section) < 1 then 0 else CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) end -- numerical sort
Section
--------------------------------------------------
BB
1
AB 1
A21
B2
A11
B20
B21
AB10
A10
Section
--------------------------------------------------
BB
1
A10
A11
A21
AB 1
AB10
B2
B20
B21
您可以像这样使用 stuff()
而不是 substring()
:
select section
, alpha = left(section,patindex('%[0-9]%',section+'0')-1)
, num = stuff(section,1,patindex('%[0-9]%',section)-1,'')
from section
order by
left(section,patindex('%[0-9]%',section+'0')-1)
, convert(int,stuff(section,1,patindex('%[0-9]%',section)-1,''))
rextester 演示:http://rextester.com/JOXUEE9700
输出:
+---------+-------+------+
| section | alpha | num |
+---------+-------+------+
| 1 | | 1 |
| A10 | A | 10 |
| A11 | A | 11 |
| A21 | A | 21 |
| AB 1 | AB | 1 |
| AB10 | AB | 10 |
| B2 | B | 2 |
| B20 | B | 20 |
| B21 | B | 21 |
| BB | BB | NULL |
+---------+-------+------+
我发现我们可以对 table 中的列进行排序,即使它是字母数字。
这里我遇到的唯一问题是,如果列数据只是字符,它会抛出错误。
BEGIN TRAN
USE SomeDatabase
CREATE TABLE dbo.Section
(
Section varchar(50) NULL
)
INSERT INTO dbo.Section (Section.Section) VALUES ('BB')
INSERT INTO dbo.Section (Section.Section) VALUES ('1 ')
INSERT INTO dbo.Section (Section.Section) VALUES ('AB 1')
INSERT INTO dbo.Section (Section.Section) VALUES ('A21')
INSERT INTO dbo.Section (Section.Section) VALUES ('B2')
INSERT INTO dbo.Section (Section.Section) VALUES ('A11')
INSERT INTO dbo.Section (Section.Section) VALUES ('B20')
INSERT INTO dbo.Section (Section.Section) VALUES ('B21')
INSERT INTO dbo.Section (Section.Section) VALUES ('AB10')
INSERT INTO dbo.Section (Section.Section) VALUES ('A10')
SELECT Section
FROM dbo.Section
SELECT Section
FROM dbo.Section
ORDER BY LEFT(Section,PATINDEX('%[0-9]%',Section)-1), -- alphabetical sort
CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) -- numerical sort
DROP Table dbo.Section
ROLLBACK
所以,排序 'BB' 就是问题所在。如果你删除 BB 那么一切正常。
从您的代码来看,一个明显的问题是 PATINDEX
如果没有找到任何东西,它将 return 0。因为您随后将 0 - 1
作为长度,所以 LEFT 函数将抛出错误。
试试这个:
...
ORDER BY LEFT(Section
,CASE WHEN PATINDEX('%[0-9]%',Section) >= 2
THEN PATINDEX('%[0-9]%',Section) - 1
ELSE LEN(Section)
END
), -- alphabetical sort
CASE WHEN PATINDEX('%[0-9]%',Section) >= 1
THEN CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section) - PATINDEX('%[0-9]%',Section) - 1))
END -- numerical sort
...
问题是 Patindex 在两个 order by 子句中都返回 0。我在下面更正了。
declare @Section TABLE
(
Section varchar(50) NULL
)
INSERT INTO @Section (Section) VALUES ('BB')
INSERT INTO @Section (Section) VALUES ('1 ')
INSERT INTO @Section (Section) VALUES ('AB 1')
INSERT INTO @Section (Section) VALUES ('A21')
INSERT INTO @Section (Section) VALUES ('B2')
INSERT INTO @Section (Section) VALUES ('A11')
INSERT INTO @Section (Section) VALUES ('B20')
INSERT INTO @Section (Section) VALUES ('B21')
INSERT INTO @Section (Section) VALUES ('AB10')
INSERT INTO @Section (Section) VALUES ('A10')
SELECT Section
FROM @Section
SELECT Section
FROM @Section
ORDER BY Section
--LEFT(Section,PATINDEX('%[0-9]%',Section)-1), -- alphabetical sort
-- CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) -- numerical sort
SELECT Section
FROM @Section
ORDER BY LEFT(Section,case when PATINDEX('%[0-9]%',Section) < 1 then 1 else PATINDEX('%[0-9]%',Section) end -1), -- alphabetical sort
case when PATINDEX('%[0-9]%',Section) < 1 then 0 else CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) end -- numerical sort
Section
--------------------------------------------------
BB
1
AB 1
A21
B2
A11
B20
B21
AB10
A10
Section
--------------------------------------------------
BB
1
A10
A11
A21
AB 1
AB10
B2
B20
B21
您可以像这样使用 stuff()
而不是 substring()
:
select section
, alpha = left(section,patindex('%[0-9]%',section+'0')-1)
, num = stuff(section,1,patindex('%[0-9]%',section)-1,'')
from section
order by
left(section,patindex('%[0-9]%',section+'0')-1)
, convert(int,stuff(section,1,patindex('%[0-9]%',section)-1,''))
rextester 演示:http://rextester.com/JOXUEE9700
输出:
+---------+-------+------+
| section | alpha | num |
+---------+-------+------+
| 1 | | 1 |
| A10 | A | 10 |
| A11 | A | 11 |
| A21 | A | 21 |
| AB 1 | AB | 1 |
| AB10 | AB | 10 |
| B2 | B | 2 |
| B20 | B | 20 |
| B21 | B | 21 |
| BB | BB | NULL |
+---------+-------+------+