Reputation: 375
I have the following SQL:
SELECT fldTitle
FROM tblTrafficAlerts
ORDER BY fldTitle
Which returns the results (from a NVARCHAR
column) in the following order:
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.
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.
Upvotes: 3
Views: 502
Reputation: 44336
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
Upvotes: 2
Reputation: 67311
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...)
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.
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
Upvotes: 0
Reputation: 3752
SELECT fldTitle FROM tblTrafficAlerts order by LEFT(fldTitle , CHARINDEX(' ', fldTitle) - 1), fldTitle
or use patindex
ORDER BY LEFT(Col1,PATINDEX('%[^0-9]%',Col1)-1)
Upvotes: 0
Reputation: 14097
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 ║
╚══════════════════════════════════════════════════════════════════╝
Upvotes: 0