I have a column in SQL Server that contains data like this:
1.1.1.QuestionText
1.1.1.Question
1.1.1(a).Questions
1.1.2.Questionswithtext
1.1.2(b).Text
10.1.1.Answers
2.1.1.Questions
2.2.2.QuestionText
How do I display this in ascending order?
This should work:
SELECT name
FROM ( SELECT name, SUBSTRING(name, 1,
LEN(name) - PATINDEX('%[0-9]%', REVERSE(name)) + 1) n
FROM #tmp
) v
ORDER BY CAST(PARSENAME(n, 4) AS INT),
CAST(PARSENAME(n, 3) AS INT),
CAST(PARSENAME(n, 2) AS INT),
CAST(PARSENAME(n, 1) AS INT)
Output:
name
1.1.1.QuestionText
1.1.1.Question
1.1.1(a).Questions
1.1.2.Questionswithtext
1.1.2(b).Text
2.1.1.Questions
2.2.2.QuestionText
10.1.1.Answers
If you want to order by text after version number then this will work:
SELECT name
FROM ( SELECT name, SUBSTRING(name, 1,
LEN(name) - PATINDEX('%[0-9]%', REVERSE(name)) + 1) nv,
SUBSTRING(name, LEN(name) - PATINDEX('%[0-9]%', REVERSE(name)) + 2,
LEN(name)) nt
FROM #tmp
) v
ORDER BY CAST(PARSENAME(nv, 4) AS INT),
CAST(PARSENAME(nv, 3) AS INT),
CAST(PARSENAME(nv, 2) AS INT),
CAST(PARSENAME(nv, 1) AS INT),
nt
Output:
name
1.1.1(a).Questions
1.1.1.Question
1.1.1.QuestionText
1.1.2(b).Text
1.1.2.Questionswithtext
2.1.1.Questions
2.2.2.QuestionText
10.1.1.Answers
You happen to have a four-part naming, so you can use parsename()
. That results in something like this:
order by (case when isnumeric(arsename(col, 4)) = 1 then cast(parsename(col, 4) as int)
end),
(case when isnumeric(parsename(col, 3)) = 1 then cast(parsename(col, 3) as int)
end),
(case when isnumeric(parsename(col, 2)) = 1 then cast(parsename(col, 2) as int)
end),
(case when isnumeric(parsename(col, 1)) = 1 then cast(parsename(col, 1) as int)
end),
col
This isn't perfect, because you seem to have oddly placed parentheses. But it might be good enough for your purposes.
Try this:
CREATE TABLE #TMP
(
name nvarchar(30)
)
INSERT INTO #TMP (name) VALUES ('1.1.1.QuestionText')
INSERT INTO #TMP (name) VALUES ('1.1.1.Question')
INSERT INTO #TMP (name) VALUES ('1.1.1(a).Questions')
INSERT INTO #TMP (name) VALUES ('1.1.2.Questionswithtext')
INSERT INTO #TMP (name) VALUES ('1.1.2(b).Text')
INSERT INTO #TMP (name) VALUES ('10.1.1.Answers')
INSERT INTO #TMP (name) VALUES ('2.1.1.Questions')
INSERT INTO #TMP (name) VALUES ('2.2.2.QuestionText')
select
SUBSTRING(replace(name, '.',''),1,
PATINDEX('%[^0-9]%',
replace(name, '.','')
) -1
) as replaced, name from #TMP order by
CAST(
SUBSTRING(replace(name, '.',''),1,
PATINDEX('%[^0-9]%',
replace(name, '.','')
) -1
)
as int)
It works always when it starts from digits. It is ordered by this first digits only. If you want to order by digits first and rest of the text later you can change last query to (I put in the select the same like in order by to show ordered parts):
select
SUBSTRING(replace(name, '.',''),1,
PATINDEX('%[^0-9]%',
replace(name, '.','')
) -1
) as replacedDigit,
SUBSTRING(replace(name, '.',''),
PATINDEX('%[^0-9]%',
replace(name, '.','')
), 100) as replacedText,
name from #TMP order by
CAST(
SUBSTRING(replace(name, '.',''),1,
PATINDEX('%[^0-9]%',
replace(name, '.','')
) -1
)
as int), SUBSTRING(replace(name, '.',''),
PATINDEX('%[^0-9]%',
replace(name, '.','')
), 100)
Try this
SELECT *
FROM t
ORDER BY
CASE PATINDEX('%[^0-9]%', PARSENAME(name, 4))
WHEN 0 THEN RIGHT('0000' + PARSENAME(name, 4), 4)
WHEN 1 THEN PARSENAME(name, 1)
ELSE RIGHT('0000' + SUBSTRING(PARSENAME(name, 2), 1, PATINDEX('%[^0-9]%', PARSENAME(name, 2)) - 1), 4) + SUBSTRING(PARSENAME(name, 2), PATINDEX('%[^0-9]%', PARSENAME(name, 2)), LEN(name))
END
, CASE PATINDEX('%[^0-9]%', PARSENAME(name, 3))
WHEN 0 THEN RIGHT('0000' + PARSENAME(name, 3), 4)
WHEN 1 THEN PARSENAME(name, 1)
ELSE RIGHT('0000' + SUBSTRING(PARSENAME(name, 2), 1, PATINDEX('%[^0-9]%', PARSENAME(name, 2)) - 1), 4) + SUBSTRING(PARSENAME(name, 2), PATINDEX('%[^0-9]%', PARSENAME(name, 2)), LEN(name))
END
, CASE PATINDEX('%[^0-9]%', PARSENAME(name, 2))
WHEN 0 THEN RIGHT('0000' + PARSENAME(name, 2), 4)
WHEN 1 THEN PARSENAME(name, 1)
ELSE RIGHT('0000' + SUBSTRING(PARSENAME(name, 2), 1, PATINDEX('%[^0-9]%', PARSENAME(name, 2)) - 1), 4) + SUBSTRING(PARSENAME(name, 2), PATINDEX('%[^0-9]%', PARSENAME(name, 2)), LEN(name))
END
, CASE PATINDEX('%[^0-9]%', PARSENAME(name, 1))
WHEN 0 THEN RIGHT('0000' + PARSENAME(name, 1), 4)
WHEN 1 THEN PARSENAME(name, 1)
ELSE RIGHT('0000' + SUBSTRING(PARSENAME(name, 2), 1, PATINDEX('%[^0-9]%', PARSENAME(name, 2)) - 1), 4) + SUBSTRING(PARSENAME(name, 2), PATINDEX('%[^0-9]%', PARSENAME(name, 2)), LEN(name))
END
For this:
1.1.1.Question
1.1.1.QuestionText
1.1.1(a).Questions
1.1.2.Questionswithtext
1.1.2(b).Text
2.1.1.Questions
2.2.2.QuestionText
10.1.1.Answers
来源:https://stackoverflow.com/questions/30426016/how-to-sort-a-varchar-datatype-column-by-its-numbers-in-sql-server