问题
How to sort a table with different numbers and characters. Column in my table is
res_no
------
B14
A6
C16
105 FF
114A
113
37
39A
91G
93
93(2)
A143B
A141
D154a
A141(25)
C40FF
D153(1)
E18A
D154
A51A
A50
E18A1
I want to sort this like
res_no
------
37
39A
91G
93
93(2)
105FF
113
114A
A6
A50
A51A
A141
A141(25)
A143B
B14
C40FF
D153(1)
D154
D154A
E18A
E18A1
I tried to ORDER BY
:
REGEXP ('^[0-9]')
CAST(res_no AS UNSIGNED)
REGEXP_SUBSTR(res_no, '(^[a-zA-Z]+)|([a-zA-Z]$)')
CAST(REGEXP_SUBSTR(res_no, '(^[0-9]+)|([0-9]+$)') AS UNSIGNED
How to solve this? Sorting numbers, alphanumerical values is working perfect with above code but values inside parentheses and like A50,A51A are not sorting correctly.
回答1:
This query should give you the results you want. The query orders on 5 things:
- A starting set of letters (if not present, this will be empty and so values starting with numbers will sort before those starting with letters);
- The first number in the string (which may be preceded by letters);
- The second set of letters in the string (if present);
- A trailing number enclosed in parentheses (if present);
- A trailing number not enclosed in parentheses (if present).
SELECT res_no
FROM table1
ORDER BY REGEXP_SUBSTR(res_no, '^[a-zA-Z]+'),
CAST(REGEXP_REPLACE(res_no, '^[a-zA-Z]*([0-9]+)', '\\1') AS UNSIGNED),
REGEXP_SUBSTR(res_no, '(?<=[0-9])[a-zA-Z]+'),
CAST(REGEXP_SUBSTR(res_no, '(?<=\\()[0-9]+(?=\\))') AS UNSIGNED),
CAST(REGEXP_SUBSTR(res_no, '[0-9]+$') AS UNSIGNED)
Output:
res_no
37
39A
91G
93
93(2)
105FF
113
114A
A6
A50
A51A
A141
A141(25)
A143B
B14
C16
C40FF
D153(1)
D154
D154a
E18A
E18A1
Demo on dbfiddle
回答2:
For the sample data that you posted this will work:
select * from tablename
order by
res_no + 0 > 0 desc,
res_no + 0,
left(res_no, 1),
substr(res_no, 2) + 0,
case
when res_no like '%(%)%' then
substring_index(substring_index(res_no, ')', 1), '(', -1) + 0
else ''
end,
length(res_no),
reverse(reverse(res_no) + 0) + 0,
right(res_no, 1)
See the demo.
Results:
| res_no |
| -------- |
| 37 |
| 39A |
| 91G |
| 93 |
| 93(2) |
| 105 FF |
| 113 |
| 114A |
| A6 |
| A50 |
| A51A |
| A141 |
| A141(25) |
| A143B |
| B14 |
| C16 |
| C40FF |
| D153(1) |
| D154 |
| D154a |
| E18A |
| E18A1 |
回答3:
This is quite tricky for me however I'm able to get your desired result with this query. Might not be the solution but hopefully you'll get ideas from it.
My approach is to:
- Extract the numbers out from the
res_no
value. I'm usingREGEXP_REPLACE
to find any alphabetic value inres_no
and replace with empty value. So the output is just (CAST AS UNSIGNED) numbers.
CAST(REGEXP_REPLACE(res_no,' *[A-Z] *', '') AS UNSIGNED) AS numbers
- Assign custom row number value by numbers as 1, A as 2, B as 3.. and so forth. So if your
res_no
value spans until Z, well..
CASE WHEN res_no REGEXP ('^[0-9]')=1 THEN 1
WHEN res_no LIKE 'A%' THEN 2
WHEN res_no LIKE 'B%' THEN 3
WHEN res_no LIKE 'C%' THEN 4
WHEN res_no LIKE 'D%' THEN 5
WHEN res_no LIKE 'E%' THEN 6
WHEN res_no LIKE 'F%' THEN 7 END AS rownum
- The last part is to do the ordering based on rownum first then numbers and I added a last condition
LENGTH(res_no)
because I was getting some ordering like the93, 93(2)
the other way around.
SELECT res_no,
CAST(REGEXP_REPLACE(res_no,' *[A-Z] *', '') AS UNSIGNED) AS numbers,
CASE WHEN res_no REGEXP ('^[0-9]')=1 THEN 1
WHEN res_no LIKE 'A%' THEN 2
WHEN res_no LIKE 'B%' THEN 3
WHEN res_no LIKE 'C%' THEN 4
WHEN res_no LIKE 'D%' THEN 5
WHEN res_no LIKE 'E%' THEN 6
WHEN res_no LIKE 'F%' THEN 7 END AS rownum
FROM TableA
ORDER BY rownum,numbers,LENGTH(res_no);
The query above generated the following output:
+----------+---------+--------+
| res_no | numbers | rownum |
+----------+---------+--------+
| 37 | 37 | 1 |
| 39A | 39 | 1 |
| 91G | 91 | 1 |
| 93 | 93 | 1 |
| 93(2) | 93 | 1 |
| 105FF | 105 | 1 |
| 113 | 113 | 1 |
| 114A | 114 | 1 |
| A6 | 6 | 2 |
| A50 | 50 | 2 |
| A51A | 51 | 2 |
| A141 | 141 | 2 |
| A141(25) | 141 | 2 |
| A143B | 143 | 2 |
| B14 | 14 | 3 |
| C40FF | 40 | 4 |
| D153(1) | 153 | 5 |
| D154 | 154 | 5 |
| D154A | 154 | 5 |
+----------+---------+--------+
Now, you make the query like below and also get the same result:
SELECT res_no
FROM TableA
ORDER BY CASE WHEN res_no REGEXP ('^[0-9]')=1 THEN 1
WHEN res_no LIKE 'A%' THEN 2
WHEN res_no LIKE 'B%' THEN 3
WHEN res_no LIKE 'C%' THEN 4
WHEN res_no LIKE 'D%' THEN 5
WHEN res_no LIKE 'E%' THEN 6
WHEN res_no LIKE 'F%' THEN 7 END,
CAST(REGEXP_REPLACE(res_no,' *[A-Z] *', '') AS UNSIGNED),
LENGTH(res_no);
Switching from SELECT
to ORDER BY
.
Btw I'm using MariaDB 10.3;
回答4:
If I understand correctly, you want leading digits first by number and the rest alphabetically following.
The following query does this:
select t.*
from t
order by (res_no + 0) > 0 desc, -- numbers first
(res_no + 0),
res_no;
Here is a db<>fiddle.
You can "special case" the a
records:
select t.*
from t
order by (res_no + 0) > 0 desc, -- numbers first
(res_no + 0),
(case when res_no like 'A%' then res_no end) desc,
res_no;
来源:https://stackoverflow.com/questions/58023005/sorting-multiple-types-of-numbers-and-characters