以特定格式提供ID
列ORDER
。列具有varchar
数据类型,并且始终具有字母值,前面通常为P
,后跟三到四个数值。可能甚至后跟下划线或其他字母值。我尝试了很少的选择,没有人回复我想要的东西。
SELECT [ID] FROM MYTABLE
ORDER BY
(1) LEN(ID), ID ASC
/ (2) LEFT(ID,2)
OPTIONS TRIED (3) SUBSTRING(ID,2,4) ASC
\ (4) ROW_NUMBER() OVER (ORDER BY SUBSTRING(ID,2,4))
(5) SUBSTRING(ID,PATINDEX('%[0-9]%',ID),LEN(ID))
(6) LEFT(ID, PATINDEX('%[0-9]%', ID)-1)
选项1似乎最接近我要查找的内容,除非_
或字母值遵循数值。参见下面选项1的结果
P100
P208
P218
P301
P305
P306
P4200
P4510
P4511
P4512
P5011
P1400A
P4125H
P4202A
P4507L
P4706A
P1001_2
P2103_B
P4368_RL
想看看..
P100
P208
P218
P301
P305
P306
P1001_2
P1400A
P2103_B
P4125H
P4200
P4202A
P4368_RL
P4507L
P4510
P4511
P4512
P4706A
P5011
答案 0 :(得分:2)
ORDER BY
CAST(SUBSTRING(id, 2, 4) AS INT),
SUBSTRING(id, 6, 3)
http://sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/9464
还有一个比getOnlyNumbers()
UDF复杂的,但应对不同长度的数字部分。
CROSS APPLY
(
SELECT
tail_start = PATINDEX('%[0-9][^0-9]%', id + '_')
)
stats
CROSS APPLY
(
SELECT
numeric = CAST(SUBSTRING(id, 2, stats.tail_start-1) AS INT),
alpha = RIGHT(id, LEN(id) - stats.tail_start)
)
id_tuple
ORDER BY
id_tuple.numeric,
id_tuple.alpha
http://sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/9499
最后,一个可以应付根本没有数字的人(但仍假设第一个角色存在且应该被忽略)。
CROSS APPLY
(
SELECT
tail_start = NULLIF(PATINDEX('%[0-9][^0-9]%', id + '_'), 0)
)
stats
CROSS APPLY
(
SELECT
numeric = CAST(SUBSTRING(id, 2, stats.tail_start-1) AS INT),
alpha = RIGHT(id, LEN(id) - ISNULL(stats.tail_start, 1))
)
id_tuple
ORDER BY
id_tuple.numeric,
id_tuple.alpha
http://sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/9507
答案 1 :(得分:2)
这是一种相当奇怪的排序方式,但现在我理解它,我找到了一个解决方案。我在这里使用表值函数来从字符串中去掉数字。由于函数返回所有数字字符,我还需要检查_并且只传递字符串中的部分。
这是功能。
create function GetOnlyNumbers
(
@SearchVal varchar(8000)
) returns table as return
with MyValues as
(
select substring(@SearchVal, N, 1) as number
, t.N
from cteTally t
where N <= len(@SearchVal)
and substring(@SearchVal, N, 1) like '[0-9]'
)
select distinct NumValue = STUFF((select number + ''
from MyValues mv2
order by mv2.N
for xml path('')), 1, 0, '')
from MyValues mv
此功能正在使用计数表。如果你有一个,你可以略微调整该代码以适应。这是我的理货表。我保留它作为一种观点。
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
GO
接下来我们当然需要一些数据才能运作。在这种情况下,我刚刚创建了一个表变量来表示您的实际表。
declare @Something table
(
SomeVal varchar(10)
)
insert @Something values
('P100')
, ('P208')
, ('P218')
, ('P301')
, ('P305')
, ('P306')
, ('P4200')
, ('P4510')
, ('P4511')
, ('P4512')
, ('P5011')
, ('P1400A')
, ('P4125H')
, ('P4202A')
, ('P4507L')
, ('P4706A')
, ('P1001_2')
, ('P2103_B')
, ('P4368_RL')
通过我们所有的腿部和设置,我们可以获得完成此任务所需的实际查询。
select s.SomeVal
from @Something s
cross apply dbo.GetOnlyNumbers(case when charindex('_', s.SomeVal) = 0 then s.SomeVal else left(s.SomeVal, charindex('_', s.SomeVal) - 1) end) x
order by convert(int, x.NumValue)
这将按您在问题中列出的顺序返回行。
答案 2 :(得分:1)
您可以逐步分解ID
以提取数字。然后,按数字和ID
排序。我喜欢使用CROSS APPLY
将长字符串操作分解为多个步骤。你可以内联(它很长)或将其捆绑成内联TVF。
SELECT t.*
FROM MYTABLE t
CROSS APPLY (SELECT NoP = STUFF(ID, 1, 1, '')) nop
CROSS APPLY (SELECT FindNonNumeric = LEFT(NoP, ISNULL(NULLIF(PATINDEX('%[^0-9]%', NoP)-1, -1), LEN(NoP)))) fnn
CROSS APPLY (SELECT Number = CONVERT(INT, FindNonNumeric)) num
ORDER BY Number
, ID;
答案 3 :(得分:0)
我认为最好的办法是创建一个从字符串中删除数字的函数,如this one,然后按此排序。更好的是,正如@SeanLange建议的那样,将使用该函数将数值存储在新列中并按此排序。