Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Re: SORTING PROBLEM WHEN NUMBERS ARE MIXED WITH LETTERS

Re: SORTING PROBLEM WHEN NUMBERS ARE MIXED WITH LETTERS

From: Glebsky <glebsky_at_gmx.net>
Date: Fri, 21 Dec 2001 13:08:25 +0600
Message-ID: <3C22DFE9.F477AFF5@gmx.net>


Hi Rob,
IMHO it would be impossible to find simple way for sorting varchars with letters and digits.
Just because there is one standart method (sorting by ASCII or some national code) everywhere. Just look at sorted list of your files (OS doesnt matter).
Having sayd that I just mean that if someone want to sort in other way than standart one than he must describe the algorithm and ... and implement it.

I'd like to offer some implementation with all its side-effects (as they are),
and wonder if you will find it acceptable. (And I would never ever would like to talk or (worst) meet with your DBA).

I also really wonder if there exists someone who knows better way out there?

Lets say that our values look like as StartingNumber, MiddleString and EndingNumber. And lets say the next:   value has very big StartingNumber if it starts from letter,   value has NULL MiddleString if it contains only digits,   value has EndingNumber set to 0 if its last character is not digit.

Than if we will select your values ordered by StartingNumber, MiddleString and EndingNumber we will get 136b before 136, TESTRUN2 after TESTRUN but before TESTRUN11.

SELECT y, s_v_p1(y), s_v_p2(y), s_v_p3(y) FROM x   ORDER BY 2, 3, 4;
-
63 63 NULL 0
136b 136 b 0
137 137 NULL 0
ab 1000000000 ab 0
ab1 1000000000 ab 1
abc2 1000000000 abc 2
abc10 1000000000 abc 10
TESTRUN 1000000000 testrun 0
TestRun 1000000000 testrun 0
TESTRUN2 1000000000 testrun 2
testrun11 1000000000 testrun 11
NULL 1000000000 NULL 0 And here are String_Value_PartX functions:

CREATE OR REPLACE FUNCTION s_v_p1(value IN VARCHAR2)   RETURN NUMBER
AS

  mid_chars VARCHAR2(255);
  mid_start NUMBER;
  MAX_VALUE NUMBER := 1000000000;

BEGIN
  mid_chars := TRIM( TRANSLATE( value,'0123456789',' ' ) );   IF mid_chars IS NULL THEN
    RETURN NVL( TO_NUMBER( value ), MAX_VALUE );   END IF;
  mid_start := INSTR( value, mid_chars );   IF mid_start <= 1 THEN
    RETURN MAX_VALUE;
  END IF;
  RETURN TO_NUMBER( SUBSTR( value, 1, mid_start-1 ) );   EXCEPTION WHEN OTHERS THEN
    RETURN MAX_VALUE;
END s_v_p1;

CREATE OR REPLACE FUNCTION s_v_p2(value IN VARCHAR2)   RETURN VARCHAR2
AS
BEGIN
  RETURN TRIM( LOWER( TRANSLATE( value,'0123456789',' ' ) ) ); END s_v_p2;

CREATE OR REPLACE FUNCTION s_v_p3(value IN VARCHAR2)   RETURN NUMBER
AS
  mid_chars VARCHAR2(255);
  mid_start NUMBER;
BEGIN
  mid_chars := TRIM( TRANSLATE( value,'0123456789',' ' ) );   IF mid_chars IS NULL THEN
    RETURN 0;
  END IF;
  mid_start := INSTR( value, mid_chars );   RETURN NVL( TO_NUMBER(
    SUBSTR( value, mid_start + LENGTH( mid_chars ) ) ), 0);   EXCEPTION WHEN OTHERS THEN
    RETURN 0;
END s_v_p3;

Regards

--

Rob Earl wrote:


> Recently I have been presented with a problem of figuring out how to
> display information from a table which has a VARCHAR2 field that can
> contain numbers as well as alphanumeric characters. When just doing a
> simply ORDER BY the fields is sorted in an ASCII way in which numbers
> are out of numeric order and are in order of there ASCII
> representation. I understand why the problem is occurring, but I'm
> stuck trying to find an easy way in SQL to sort these values properly.
> To make things a little tricker, there can be a mixture of
> alphanumeric characters as well as numbers. Here is some example data
> as seen with just a plain ORDER BY sort:
>
> 136b
> 137
> 138
> 220
> 238
> 239
> 60
> 61
> 62
> 63
> TESTRUN
> TESTRUN2
> TestRun
> ab
> abc10
> abc2
>
> Through searching the USENET I did manage to come up with an SQL
> statement that comes really really close to solving the problem:
>
> select NAME, nvl( trim (trailing from translate( lpad(NAME,40,' '),
> '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
> '1234567890' ) ), NAME) new_a
> from table1
> order by new_a;
>
> That statement returns the following:
>
> 60
> 61
> 62
> 63
> 137
> 138
> 220
> 238
> 239
> 136b
> abc2
> abc10
> TESTRUN2
> TESTRUN
> TestRun
> ab
>
> This was really close, but what the statement works best with is if
> the field only contains JUST numbers or JUST letters. If there is a
> mixture of both it kind of gets screwed up. The line out of place is
> the 136b. It really should be right before the 137 line.
>
> This seems like it should be a real common problem, considering this
> type of data must exist in many systems. Does anyone out there have
> any idea how I could possibly get my data to sort properly? When I
> say properly, I mean that it would be sorted like the following:
>
> 60
> 61
> 62
> 63
> 136b
> 137
> 138
> 220
> 238
> 239
> abc2
> abc10
> TESTRUN2
> TESTRUN
> TestRun
> ab
>
> In a nutshell, this means that to be sorted properly all lines
> starting with a number would come first, followed by lines starting
> with letters. If the letter lines have numbers, they would proceed
> any lines that have ONLY letters. This seems like a fairly normal
> sort order to me.
>
> Thanks in advance for any help. I appreciate it greatly.
>
> Rob
Received on Fri Dec 21 2001 - 01:08:25 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US