Skip to content
Advertisement

Sort alphanumeric ID number

I have a database that every transactions get a alphanumeric ID. By when I write my query and use Order by it give me a wrong sequence.

For example:

TRN_ID      TRNDTE
000002DAAW  2020-09-12 03:45:24
000002DAAX  2020-09-12 03:45:32
000002DAAY  2020-09-12 03:45:34
000002DAAZ  2020-09-12 03:45:38
000002DAA0  2020-09-12 03:35:16
000002DAA1  2020-09-12 03:35:25
000002DAA2  2020-09-12 03:35:26
000002DAA3  2020-09-12 03:35:30
000002DAA4  2020-09-12 03:35:39
000002DAA5  2020-09-12 03:35:40
000002DAA6  2020-09-12 03:35:44
000002DAA7  2020-09-12 03:36:00
000002DAA8  2020-09-12 03:36:01
000002DAA9  2020-09-12 03:36:05
000002DABA  2020-09-12 03:48:12 <-
000002DABB  2020-09-12 03:48:15
000002DABC  2020-09-12 03:48:32
000002DABD  2020-09-12 03:48:33
000002DABE  2020-09-12 03:48:36
000002DABF  2020-09-12 03:48:46
000002DABG  2020-09-12 03:48:47
000002DABH  2020-09-12 03:48:50
000002DABI  2020-09-12 03:49:06
000002DABJ  2020-09-12 03:49:06
000002DABK  2020-09-12 03:49:09
000002DABL  2020-09-12 03:49:19
000002DABM  2020-09-12 03:49:20
000002DABN  2020-09-12 03:49:24
000002DABO  2020-09-12 03:49:33
000002DABP  2020-09-12 03:49:34
000002DABQ  2020-09-12 03:49:37
000002DABR  2020-09-12 03:49:48
000002DABS  2020-09-12 03:49:48
000002DABT  2020-09-12 03:49:51
000002DABU  2020-09-12 03:50:01
000002DABV  2020-09-12 03:50:01
000002DABW  2020-09-12 03:50:05
000002DABX  2020-09-12 03:50:15
000002DABY  2020-09-12 03:50:15
000002DABZ  2020-09-12 03:50:18
000002DAB0  2020-09-12 03:46:23 <-
000002DAB1  2020-09-12 03:46:24
000002DAB2  2020-09-12 03:46:28
000002DAB3  2020-09-12 03:47:18
000002DAB4  2020-09-12 03:47:18

As you can see the query is ordering A to Z then 0 to 9, but it should order 0 to 9 then A to Z

There is a way set a string to order it correctly?

Advertisement

Answer

It is very likely that Trincot’s observation (second comment under your question) is correct: You see ascending ordering with letters before digits (instead of the opposite), because your collation requires it.

From your profile I assume you are in Brazil, and your NLS_LANGUAGE parameter is 'BRAZILIAN PORTUGUESE', with the default NLS_SORT parameter (derived from NLS_LANGUAGE) of 'WEST_EUROPEAN'. It’s not Oracle’s choice; Brazilian Portuguese collation (or, rather more accurately, West-European collation) has digits after letters, not before them. See a demo at the end of this answer.

So, this explains the problem. How can you fix it?

If you have a lot of similar queries, and you must show digits before letters in all of them (or if you have ORDER BY in many places in a query – for example in analytic functions, or in match_recognize, etc.), then it makes sense to change the NLS_SORT parameter for the session, with

alter session set nls_sort='BINARY';

If you only need to do it in a single query, in the ORDER BY clause, you can just change the sort order locally (for that ORDER BY clause only, without affecting anything else) by using the NLSSORT function. Like this:

.... order by nlssort(TRN_ID, 'NLS_SORT=BINARY')

Here is a brief demo.

First, on my system, NLS_LANGUAGE is 'AMERICAN', with the default NLS_SORT (for this language) of 'BINARY'. This is why letters come after digits:

select col
from   (select 'A' as col from dual union all select '3' from dual)
order  by col;

COL
---
3
A

Now let me change my NLS_LANGUAGE to 'BRAZILIAN PORTUGUESE'. Then let’s see how this affected NLS_SORT (automatically), and what that does to the query:

alter session set nls_language='BRAZILIAN PORTUGUESE';

select parameter, value
from   v$nls_parameters
where  parameter in ('NLS_LANGUAGE', 'NLS_SORT');

PARAMETER    VALUE                 
------------ ----------------------
NLS_LANGUAGE BRAZILIAN PORTUGUESE  
NLS_SORT     WEST_EUROPEAN       



select col
from   (select 'A' as col from dual union all select '3' from dual)
order  by col;

COL
---
A
3

Now, without changing the language, let me just change the collating sequence (NLS_SORT parameter) to 'BINARY' – and see how the query produces the desired result. We didn’t change the language, but we changed the collating sequence for the entire session. This will work for all other queries in the current session.

alter session set nls_sort='BINARY';

select parameter, value
from   v$nls_parameters
where  parameter in ('NLS_LANGUAGE', 'NLS_SORT');

PARAMETER    VALUE                 
------------ ----------------------
NLS_LANGUAGE BRAZILIAN PORTUGUESE  
NLS_SORT     BINARY 




select col
from   (select 'A' as col from dual union all select '3' from dual)
order  by col;

COL
---
3
A   

Finally, let me change NLS_SORT back to 'WEST_EUROPEAN' and use the NLSSORT function in the ORDER BY clause of the query to get the same result (the one you need) without touching the session parameters.

alter session set nls_sort='WEST_EUROPEAN';

select col
from   (select 'A' as col from dual union all select '3' from dual)
order  by col;   -- This will produce the wrong order! See below for fix.

COL
---
A
3  

select col
from   (select 'A' as col from dual union all select '3' from dual)
order  by nlssort(col, 'nls_sort=BINARY');

COL
---
3
A
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement