Reputation: 13
I need help to order the next statement:
select numbering from QuestionnaireQuestion where
QuestionnaireQuestion.questionnaire_id = 20 AND
QuestionnaireQuestion.numbering is not null
order by LEFT(numbering,PATINDEX('%[0-9]%',numbering)-1)
the result is:
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
The last is Q1, but i need to Q1 in the TOP
Upvotes: 0
Views: 51
Reputation: 33581
The real challenge here is that your are storing multiple pieces of information in a single tuple. This violates 1NF and is truly awful to work with. Since you have a varying number of elements this is even more difficult. Assuming you never exceed 3 elements you can use some ugly string manipulation as a hack to make this work. Please note the performance of this is not going to scale well but that is because the design is less than optimal.
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))
Upvotes: 0
Reputation: 35583
I believe you need the substring, not the left
order by substring(numbering,PATINDEX('%[0-9]%',numbering),100)
however this will not solve for 10 and above, but the following will:
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
It "left pads" the first number found e.g. 6 becomes 0006 or 91 become 0091 and so on.
The cross apply is used to calculate 2 positions in the string, where the first number is found, and where the first period is found (& note a period is added to ensure this is always positive). From these positions the first number is isolated and then concatenated to '0000' eg. 6 becomes 00006 or 91 becomes 000091, then only the right 4 chars are used so we get 0001 .... 9999 possibilities.
dbfiddle demo here
Upvotes: 1