Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting hierarchical text in SQL

I've a table with a varchar field. This field stores hierarchical numbers which I want to order.

Here is an example of my data:

1
1.1
1.1.1
1.1.2
1.1.3.
1.1.4
1.1.5
1.1.6.
1.1.7
10.
10.1
10.2
10.3
11.
11.1
11.2
2.
2.1
1.2.2
1.2.2.1
1.2.2.2

How can I achieve the following result with T-SQL:

1
1.1
1.1.1
1.1.2
1.1.3
1.1.4
1.1.5
1.1.6
1.1.7
1.2.2
1.2.2.1
1.2.2.2
2.
2.1
10.
10.1
10.2
10.3
11.
11.1
11.2

I tried to split up the parts with the following SQL, but that's not elegant.

SELECT CASE WHEN CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.',''))  = 0
  THEN SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','') 
  ELSE REPLACE(SUBSTRING(SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.',''),1, CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.',''))),'.','')
  END AS FIRST_PART
 ,CASE WHEN CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.',''))  > 0
      THEN SUBSTRING( 
SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','') 
   ,CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','')) +1
   ,LEN( SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','')  )
   )
  ELSE '0'
  END AS SECOND_PART
FROM TEST_TABLE

Is theree a better way to do this?

like image 669
h0mebrewer Avatar asked Apr 17 '15 08:04

h0mebrewer


People also ask

How do you sort text in SQL?

The SQL ORDER BY Keyword The ORDER BY keyword is used to sort the result-set in ascending or descending order. The ORDER BY keyword sorts the records in ascending order by default. To sort the records in descending order, use the DESC keyword.

Can we use SQL for hierarchical database?

Use hierarchyid as a data type to create tables with a hierarchical structure, or to describe the hierarchical structure of data that is stored in another location. Use the hierarchyid functions in Transact-SQL to query and manage hierarchical data.


1 Answers

Try this:

DECLARE @DataSource TABLE
(
    [Value] VARCHAR(12)
);

INSERT INTO @DataSource ([Value])
VALUES ('1')
      ,('1.1')
      ,('1.1.1')
      ,('1.1.2')
      ,('1.1.3.')
      ,('1.1.4')
      ,('1.1.5')
      ,('1.1.6.')
      ,('1.1.7')
      ,('10.')
      ,('10.1')
      ,('10.2')
      ,('10.3')
      ,('11.')
      ,('11.1')
      ,('11.2')
      ,('2.')
      ,('2.1')
      ,('1.2.2')
      ,('1.2.2.1')
      ,('1.2.2.2');

SELECT *
FROM @DataSource
ORDER BY CAST('/' + IIF(RIGHT([Value],1) = '.', LEFT([Value], LEN([Value]) - 1), [Value]) + '/' AS HIERARCHYID);

You can check the hierarchyid for more details. The check in the ORDER BY clause is just removing the . at the end of the value (if such exist).


You can change the IIF function with simple CASE WHEN like this:

SELECT *
FROM @DataSource
ORDER BY CAST('/' + CASE WHEN  RIGHT([Value],1) = '.' THEN LEFT([Value], LEN([Value]) - 1) ELSE [Value] END + '/' AS HIERARCHYID);
like image 153
gotqn Avatar answered Oct 11 '22 21:10

gotqn