Reputation: 746
Below are the column data(ORDER) of one of my table (MyTABLE),
a
a.1
a.1.1
a.2.0
a.1.10
a.1.4
a.20.1
a.2.2.1
a.4.3.1
a.4
a.40
I want to order it in the below way,
a
a.1
a.1.1
a.1.4
a.2.0
a.2.2.1
a.4
a.4.3.1
a.20.1
a.40
b.*....(if any data present which has b prefixed etc.,)
I would be wondering if this can be achieved at database level itself while fetching results? If not then how would we do it in java?
Upvotes: 1
Views: 432
Reputation: 168001
Oracle 11g R2 Schema Setup:
CREATE TABLE MyTable ( name ) AS
SELECT 'a' FROM DUAL
UNION ALL SELECT 'a.1.4' FROM DUAL
UNION ALL SELECT 'a.2.2.1' FROM DUAL
UNION ALL SELECT 'a.1.1' FROM DUAL
UNION ALL SELECT 'a.1' FROM DUAL
UNION ALL SELECT 'a.40' FROM DUAL
UNION ALL SELECT 'a.4' FROM DUAL
UNION ALL SELECT 'a.4.3.1' FROM DUAL
UNION ALL SELECT 'a.20.1' FROM DUAL
UNION ALL SELECT 'b.1' FROM DUAL
UNION ALL SELECT 'a.2.0' FROM DUAL
Query 1:
SELECT *
FROM MyTable
ORDER BY
REGEXP_SUBSTR( name, '[^.]+', 1, 1 ),
TO_NUMBER( REGEXP_SUBSTR( name, '[^.]+', 1, 2 ) ) NULLS FIRST,
TO_NUMBER( REGEXP_SUBSTR( name, '[^.]+', 1, 3 ) ) NULLS FIRST,
TO_NUMBER( REGEXP_SUBSTR( name, '[^.]+', 1, 4 ) ) NULLS FIRST
| NAME |
|---------|
| a |
| a.1 |
| a.1.1 |
| a.1.4 |
| a.2.0 |
| a.2.2.1 |
| a.4 |
| a.4.3.1 |
| a.20.1 |
| a.40 |
| b.1 |
MySQL 5.6 Schema Setup:
CREATE TABLE MyTable ( name VARCHAR(20) );
INSERT INTO MyTable
SELECT 'a' FROM DUAL
UNION ALL SELECT 'a.1.4' FROM DUAL
UNION ALL SELECT 'a.2.2.1' FROM DUAL
UNION ALL SELECT 'a.1.1' FROM DUAL
UNION ALL SELECT 'a.1' FROM DUAL
UNION ALL SELECT 'a.40' FROM DUAL
UNION ALL SELECT 'a.4' FROM DUAL
UNION ALL SELECT 'a.4.3.1' FROM DUAL
UNION ALL SELECT 'a.20.1' FROM DUAL
UNION ALL SELECT 'b.1' FROM DUAL
UNION ALL SELECT 'a.2.0' FROM DUAL;
Query 1:
SELECT name
FROM MyTable
ORDER BY
SUBSTRING_INDEX( name, '.', 1 ),
CASE WHEN SUBSTRING_INDEX( name, '.', 2 ) = SUBSTRING_INDEX( name, '.', 1 ) THEN -1 ELSE CAST( SUBSTRING_INDEX( SUBSTRING_INDEX( name, '.', 2 ), '.', -1 ) AS SIGNED ) END,
CASE WHEN SUBSTRING_INDEX( name, '.', 3 ) = SUBSTRING_INDEX( name, '.', 2 ) THEN -1 ELSE CAST( SUBSTRING_INDEX( SUBSTRING_INDEX( name, '.', 3 ), '.', -1 ) AS SIGNED ) END,
CASE WHEN SUBSTRING_INDEX( name, '.', 4 ) = SUBSTRING_INDEX( name, '.', 3 ) THEN -1 ELSE CAST( SUBSTRING_INDEX( SUBSTRING_INDEX( name, '.', 4 ), '.', -1 ) AS SIGNED ) END
| name |
|---------|
| a |
| a.1 |
| a.1.1 |
| a.1.4 |
| a.2.0 |
| a.2.2.1 |
| a.4 |
| a.4.3.1 |
| a.20.1 |
| a.40 |
| b.1 |
Upvotes: 3
Reputation: 141
It is possible but suggest you to go this way only if you know your data well and can handle number format exception.
SELECT *
FROM TABLE
ORDER BY
TO_NUMBER(SUBSTR( REPLACE(column,'a.'),1,
INSTR(REPLACE(column,'a.'),'.')
) ||
SUBSTR( REPLACE(column,'a.'),
INSTR(REPLACE(column,'a.'),'.'),
LENGTH(REPLACE(column,'a.'))
))
How does this order by work:
Once you get your data in above numerical form, the order will work as you expecting.
Again this is very specific scenario, your data may be more patterns than this.
Upvotes: 1