简体   繁体   中英

how i can take order by while using nvarchar column in sql

I have a query like this:

SELECT [Drug_id]
FROM tbl_Receiving
ORDER BY CAST(SUBSTRING([Drug_id], 3, LEN([Drug_ID])) as int)

but result is getting

A-1
A-10A
A-11
A-2
A-20A
A-21
A-22
A-3
A-30
A-31

But I need to get in all proper ascending order.

   A-1
   A-2
   A-3
   A-10
   A-11

My [Drug_id] column is nvarchar(50)

Assuming that your format is always A-<NUMBER> , you could always do the following:

SELECT 
    [Drug_id]
FROM 
    tbl_Receiving
ORDER BY 
    CAST(SUBSTRING([Drug_id], 3, LEN([Drug_ID])) as int)

This will then only try cast from the number onwards as an int

Output will be the following:

在此输入图像描述

If the string formatting is defined as you shown in your sample data, You can use SUBSTRING and CHARINDEX to split the string before (-) and the INT value after (-). Then you can apply Ordering on them to get your desired data.

Note: Ofcourse there are performance issue with those String operations.

SELECT *
FROM your_tabele
ORDER BY SUBSTRING(val,1,CHARINDEX('-',Val,1)-1),
CAST(SUBSTRING(val,CHARINDEX('-',Val,1)+1,LEN(val)-CHARINDEX('-',Val,1)) AS INT)

Try this: Run this query

    select substring(drug_id,1,CHARINDEX('-',drug_id)) + convert(varchar,cast(substring(drug_id,CHARINDEX('-',drug_id)+1,len(drug_id)) as int)) id from tbl_Receiving
order by  cast(substring(drug_id,CHARINDEX('-',drug_id)+1,len(drug_id)) as int)

I've basically copied this from this answer: https://stackoverflow.com/a/16667778/9101689

It uses patindex to identify the position of the numeric values and substrings out the actual value. We take that substring and the use the LEFT function to trim everything out to the right and cast that value as an int to order.

declare @d table (drug_id nvarchar(max))
insert into @d values ('A-1'),('A-10A'),('A-11'),('A-2'),('A-20A'),('A-21'),('A-22'),('A-3'),('A-30'),('A-31')
SELECT *
FROM (
    SELECT ORD_subsrt = SUBSTRING(drug_id, ORD_pos, LEN(drug_id)), *
    FROM (
        SELECT ORD_pos = PATINDEX('%[0-9]%', drug_id), *
        FROM @d
    ) d
) t
Order by cast(LEFT(ORD_subsrt, PATINDEX('%[^0-9]%', ORD_subsrt + 't') - 1) as int)

The value t is added so the patindex '%[^0-9]%' will return a non zero value in the case there is no non numeric suffix on drug_id field.

Or less readable:

SELECT *
From @d
Order by cast(LEFT(SUBSTRING(drug_id, PATINDEX('%[0-9]%', drug_id), LEN(drug_id)), PATINDEX('%[^0-9]%', SUBSTRING(drug_id, PATINDEX('%[0-9]%', drug_id), LEN(drug_id)) + 't') - 1) as int)

This won't work properly if you have a value like "A2-10A" though (or anything with more than one numeric value).

If your values are always of the form:

<letter>-<number><optional letter>

Then, you can do:

order by (case when drug_id like '%[A-Z]'
               then len(drug_id) - 1  -- ignore the last character
               else len(drug_id)
          end)
         drug_id

This treats the drug_id as a string, using the length to control the ordering of the numbers. It works when:

  • the numbers are integers
  • the numbers are not not zero padded
  • the prefix is of fixed length

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM