简体   繁体   English

如何按数字顺序对字母数字SQL Server NVARCHAR列进行排序?

[英]How do I sort an alphanumeric SQL Server NVARCHAR column in numerical order?

I have the following SQL: 我有以下SQL:

SELECT fldTitle 
FROM tblTrafficAlerts 
ORDER BY fldTitle

Which returns the results (from a NVARCHAR column) in the following order: 它按以下顺序返回结果(来自NVARCHAR列):

A1M northbound within J17 Congestion
M1 J19 southbound exit Congestion
M1 southbound between J2 and J1 Congestion
M23 northbound between J8 and J7 Congestion
M25 anti-clockwise between J13 and J12 Congestion
M25 clockwise between J8 and J9 Broken down vehicle
M3 eastbound at the Fleet services between J5 and J4A Congestion
M4 J19 westbound exit Congestion

You'll see the M23 and M25 are listed above the M3 and M4 rows, which doesn't look pleasing to the eye and if scanning a much longer list of results you'd not expect to read them in this order. 您会看到M23和M25列在M3和M4行的上方,这看起来并不令人满意,如果扫描更长的结果列表,您不希望按此顺序读取它们。

Therefore I would like the results sorted alphabetically, then numerically, to look like: 因此,我希望结果按字母顺序排序,然后按数字排序,看起来像:

A1M northbound within J17 Congestion
M1 J19 southbound exit Congestion
M1 southbound between J2 and J1 Congestion
M3 eastbound at the Fleet services between J5 and J4A Congestion
M4 J19 westbound exit Congestion
M23 northbound between J8 and J7 Congestion
M25 anti-clockwise between J13 and J12 Congestion
M25 clockwise between J8 and J9 Broken down vehicle

So M3 and M4 appear above M23 and M25. 因此M3和M4出现在M23和M25之上。

This should handle it. 这应该处理它。 Also added some strange data to make sure the ordering also works on that: 还添加了一些奇怪的数据,以确保订单也适用于:

SELECT x
FROM 
(values
('A1M northbound within J17 Congestion'),
('M1 J19 southbound exit Congestion'),
('M1 southbound between J2 and J1 Congestion'),
('M23 northbound between J8 and J7 Congestion'),
('M25 anti-clockwise between J13 and J12 Congestion'),
('M25 clockwise between J8 and J9 Broken down vehicle'),
('M3 eastbound at the Fleet services between J5 and J4A Congestion'),
('M4 J19 westbound exit Congestion'),('x'), ('2'), ('x2')) x(x)
ORDER BY
  LEFT(x, patindex('%_[0-9]%', x +'0')), 
  0 + STUFF(LEFT(x, 
  PATINDEX('%[0-9][^0-9]%', x + 'x1x')),1,
  PATINDEX('%_[0-9]%', x + '0'),'')

Result: 结果:

2
A1M northbound within J17 Congestion
M1 J19 southbound exit Congestion
M1 southbound between J2 and J1 Congestion
M3 eastbound at the Fleet services between J5 and J4A Congestion
M4 J19 westbound exit Congestion
M23 northbound between J8 and J7 Congestion
M25 anti-clockwise between J13 and J12 Congestion
M25 clockwise between J8 and J9 Broken down vehicle
x
x2

Perhaps this is not beautiful, but it does work: 也许这不是很美,但确实有效:

DECLARE @tblTrafficAlerts  TABLE
(
    fldTitle NVARCHAR(500)
);

INSERT INTO @tblTrafficAlerts  (fldTitle)
VALUES (N'A1M northbound within J17 Congestion')
    , (N'M1 J19 southbound exit Congestion')
    , (N'M1 southbound between J2 and J1 Congestion')
    , (N'M23 northbound between J8 and J7 Congestion')
    , (N'M25 anti-clockwise between J13 and J12 Congestion')
    , (N'M25 clockwise between J8 and J9 Broken down vehicle')
    , (N'M3 eastbound at the Fleet services between J5 and J4A Congestion')
    , (N'M4 J19 westbound exit Congestion');

SELECT *
FROM @tblTrafficAlerts AS T
CROSS APPLY (SELECT PATINDEX('%[0-9]%', T.fldTitle)) AS N(NumIndex)
CROSS APPLY (SELECT PATINDEX('%[0-9][^0-9]%', T.fldTitle)) AS NN(NextLetter)
ORDER BY SUBSTRING(T.fldTitle, 0, N.NumIndex), CONVERT(INT, SUBSTRING(T.fldTitle, N.NumIndex, NN.NextLetter - 1));

This will extract everything before first number, order by it, then extract that number and order by it as an integer. 这将在第一个数字之前提取所有内容,按顺序提取,然后将该数字和顺序提取为整数。

That's output: 这是输出:

╔══════════════════════════════════════════════════════════════════╗
║                             fldTitle                             ║
╠══════════════════════════════════════════════════════════════════╣
║ A1M northbound within J17 Congestion                             ║
║ M1 J19 southbound exit Congestion                                ║
║ M1 southbound between J2 and J1 Congestion                       ║
║ M3 eastbound at the Fleet services between J5 and J4A Congestion ║
║ M4 J19 westbound exit Congestion                                 ║
║ M23 northbound between J8 and J7 Congestion                      ║
║ M25 anti-clockwise between J13 and J12 Congestion                ║
║ M25 clockwise between J8 and J9 Broken down vehicle              ║
╚══════════════════════════════════════════════════════════════════╝
SELECT fldTitle FROM tblTrafficAlerts order by LEFT(fldTitle , CHARINDEX(' ', fldTitle) - 1), fldTitle 

或使用patindex

ORDER BY LEFT(Col1,PATINDEX('%[^0-9]%',Col1)-1)

I'd go like this: 我会这样:

EDIT: I separated this in two portiions: The leading letter and the second part. 编辑:我把它分成两个部分:主要字母和第二部分。 This allows you to - if needed - treat the second part numerically (but there is a disturbing "M" in the first row...) 这允许你 - 如果需要 - 以数字方式处理第二部分(但第一行中有一个令人不安的“M”......)

It would be easier to do just the second step: Cut at the first blank, check the length and add a '0' on sorting if needed. 只做第二步会更容易:在第一个空白处剪切,检查长度并在需要时在排序上添加“0”。

DECLARE @tblTrafficAlerts TABLE(fldTitle VARCHAR(500));

INSERT INTO @tblTrafficAlerts VALUES 
 ('A1M northbound within J17 Congestion')
,('M1 J19 southbound exit Congestion')
,('M1 southbound between J2 and J1 Congestion')
,('M23 northbound between J8 and J7 Congestion')
,('M25 anti-clockwise between J13 and J12 Congestion')
,('M25 clockwise between J8 and J9 Broken down vehicle')
,('M3 eastbound at the Fleet services between J5 and J4A Congestion')
,('M4 J19 westbound exit Congestion');

SELECT ta.fldTitle
      ,Leading.Letter
      ,Leading.SecondPart
FROM @tblTrafficAlerts AS ta
CROSS APPLY(SELECT SUBSTRING(ta.fldTitle,1,1) AS Letter
                  ,SUBSTRING(ta.fldTitle,2,CHARINDEX(' ',ta.fldTitle)-1) AS SecondPart) AS Leading
ORDER BY Leading.Letter,CASE WHEN LEN(Leading.SecondPart)=1 THEN Leading.SecondPart + '0' ELSE Leading.SecondPart END

The result: 结果:

fldTitle                                                           Letter   SecondPart
A1M northbound within J17 Congestion                               A        1M 
M1 J19 southbound exit Congestion                                  M        1 
M1 southbound between J2 and J1 Congestion                         M        1 
M23 northbound between J8 and J7 Congestion                        M        23 
M25 anti-clockwise between J13 and J12 Congestion                  M        25 
M25 clockwise between J8 and J9 Broken down vehicle                M        25 
M3 eastbound at the Fleet services between J5 and J4A Congestion   M        3 
M4 J19 westbound exit Congestion                                   M        4 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM