在SQL Server中对字母数字进行排序

时间:2017-11-29 21:48:08

标签: sql-server

我需要帮助来订购下一个声明:

select numbering from QuestionnaireQuestion where  
QuestionnaireQuestion.questionnaire_id = 20 AND 
    QuestionnaireQuestion.numbering is not null
    order by LEFT(numbering,PATINDEX('%[0-9]%',numbering)-1)

结果是:

Q2
Q2.a
Q2.b
Q3
Q4
Q4.a
Q5
Q6
Q6.a
Q6.a.1
Q6.a.2
Q6.a.3
Q6.a.4
Q7
Q8
Q8.a
Q9
Q10
Q10.a
Q10.b
Q11
Q11.a
Q12
Q12.a
Q12.b
Q13
Q13.a
Q13.a.1
Q13.a.2
Q13.a.3
Q13.a.4
Q13.a.5
Q13.a.6
Q13.a.7
Q13.a.8
Q13.b
Q13.b.1
Q13.b.2
Q13.b.3
Q13.b.4
Q13.b.5
Q13.b.6
Q13.b.7
Q13.b.8
Q1

最后一个是Q1,但我需要TOP中的Q1

2 个答案:

答案 0 :(得分:1)

我相信你需要子串,而不是左边的

order by substring(numbering,PATINDEX('%[0-9]%',numbering),100)

然而,这不会解决10及以上,但以下将:

select numbering , right('0000'+substring(numbering,pos1,pos2-pos1),4)
from QuestionnaireQuestion 
cross apply (
      select PATINDEX('%[0-9]%',rtrim(numbering)), PATINDEX('%[.]%',rtrim(numbering)+'.')
   ) ca (pos1, pos2)
order by right('0000'+substring(numbering,pos1,pos2-pos1),4), numbering

它"左脚垫"发现的第一个号码6变为0006或91变为0091等等。

交叉应用用于计算字符串中的2个位置,其中找到第一个数字,以及找到第一个句点的位置(&注意添加一个句点以确保此值始终为正)。从这些位置开始,第一个数字被隔离,然后连接到' 0000'例如。 6变为00006或91变为000091,则只使用右4个字符,因此我们得到0001 .... 9999种可能性。

dbfiddle demo here

答案 1 :(得分:0)

这里真正的挑战是你将多个信息存储在一个元组中。这违反了1NF并且真的很糟糕。由于你有不同数量的元素,这更加困难。假设你永远不会超过3个元素,你可以使用一些丑陋的字符串操作作为黑客来使这项工作。请注意,这种情况的表现不会很好,但这是因为设计不够理想。

declare @Something table (SomeValue varchar(20))

insert @Something (SomeValue) values
('Q2')
, ('Q2.a')
, ('Q2.b')
, ('Q3')
, ('Q4')
, ('Q4.a')
, ('Q5')
, ('Q6')
, ('Q6.a')
, ('Q6.a.1')
, ('Q6.a.2')
, ('Q6.a.3')
, ('Q6.a.4')
, ('Q7')
, ('Q8')
, ('Q8.a')
, ('Q9')
, ('Q10')
, ('Q10.a')
, ('Q10.b')
, ('Q11')
, ('Q11.a')
, ('Q12')
, ('Q12.a')
, ('Q12.b')
, ('Q13')
, ('Q13.a')
, ('Q13.a.1')
, ('Q13.a.2')
, ('Q13.a.3')
, ('Q13.a.4')
, ('Q13.a.5')
, ('Q13.a.6')
, ('Q13.a.7')
, ('Q13.a.8')
, ('Q13.b')
, ('Q13.b.1')
, ('Q13.b.2')
, ('Q13.b.3')
, ('Q13.b.4')
, ('Q13.b.5')
, ('Q13.b.6')
, ('Q13.b.7')
, ('Q13.b.8')
, ('Q1')
, ('Q11')


select *

from @Something s
order by reverse(PARSENAME(reverse(s.SomeValue), 1))
    , reverse(PARSENAME(reverse(s.SomeValue), 2))
    , reverse(PARSENAME(reverse(s.SomeValue), 3))
    --If you have 4 elements you can add one more level. 
    --But this will not work if you exceed 4 elements because of how PARSENAME works.
    --, reverse(PARSENAME(reverse(s.SomeValue), 4))