Shree
Shree

Reputation: 4747

Oracle/MYSQL: Sort records from a select query on a column that contains alphanumeric values

I know that this question has been asked in various forms but my requirement happens to be a bit different.

Suppose I have a table that contains data as follows:

ID  NAME        VALUE

-----------------------------

1   ABC-2-2     X
2   PQRS-1-3    Y
3   ABC-3-2     Z
4   PQRS-1-4    A
5   PQRS-3-4    B
6   MNO-2-1     C
7   AAA-1       D
8   BBB-2       E
9   CCC-3       F

Now, the output that I'm expecting should look something like this:

ID  NAME        VALUE

-----------------------------
7   AAA-1       D
2   PQRS-1-3    Y
4   PQRS-1-4    A
8   BBB-2       E
6   MNO-2-1     C
1   ABC-2-2     X
9   CCC-3       F
3   ABC-3-2     Z
5   PQRS-3-4    B

Note that this is not a direct alpha-numeric sort. Instead, the value before the first "-" is ignored and the fields are sorted on what is after the first "-" in the name.

I'm not very familiar with PL/SQL and any kind of help on this would be appreciated.

Thanks.

PS: Note that this should work on both Oracle and MySQL.

Upvotes: 0

Views: 779

Answers (3)

Tony Andrews
Tony Andrews

Reputation: 132570

For your example this would suffice (Oracle syntax):

ORDER BY SUBSTR(name,4)

If the number of characters before the first hyphen can vary, you can do this (again Oracle syntax):

ORDER BY SUBSTR(name,INSTR(name,'-')+1)

However that won't work if you have codes like:

AAA-10-1
AAA-8-1
AAA-9-1

and expect AAA-10-1 to appear after AAA-9-1. Then you will need to parse it further:

ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name,'-',1,2)-INSTR(name,'-')-1),10,'0'),
         LPAD(SUBSTR(name,INSTR(name,'-',1,2)+1),10,'0')

(NB I have used LPAD(x,10,'0') to turn a value like '1' into '0000000001' and so on, rather than use TO_NUMBER since this could fail if there are any non-numerics in your data.)

Example:

with data as
(
select 'AAA-1' name from dual
union all
select 'PQR-1-4' name from dual
union all
select 'PQR-1-3' name from dual
union all
select 'AAA-10-10' name from dual
union all
select 'AAA-10-1' name from dual
union all
select 'AAA-9-10' name from dual
union all
select 'AAA-9-1' name from dual
)
select *
from data
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name,'-',1,2)-INSTR(name,'-')-1),10,'0'),
         LPAD(SUBSTR(name,INSTR(name,'-',1,2)+1),10,'0');

Output:

NAME
---------
PQR-1-3
PQR-1-4
AAA-9-1
AAA-9-10
AAA-10-1
AAA-10-10
AAA-1

And if AAA-1 should come first:

ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name||'-','-',1,2)-INSTR(name,'-')-1),10,'0'),
         LPAD(SUBSTR(name,INSTR(name||'-','-',1,2)+1),10,'0') nulls first

Upvotes: 2

Ranjit Singh
Ranjit Singh

Reputation: 3735

in mssql the syntax of finding your problem is :

select * from mytable order by substring(name,PATINDEX('%-%',name)+1,len(name)-PATINDEX('%-%',name))

SqlFiddle

Upvotes: 0

OldProgrammer
OldProgrammer

Reputation: 12169

Not sure about mysql syntax, but you can do this in oracle:

select * from  <your_table>
order by substr(name, 5)

Upvotes: 0

Related Questions