简体   繁体   中英

MySQL ORDER BY using a CASE statement?

I have a MySQL table which has a column containing VARCHAR data. The data could be of the following type:

  • Simple integer (1,2,3, etc.)
  • Integer appended with the letter 'L', for example (L1, L2, etc.)
  • Integer appended with the letter 'Q', for example (Q1, Q2, etc.)
  • Integer appended with the letter 'W', for example (W1, W2, etc.)

I need to pull the data from the table and sort the data matching this column, let's call it type . The sorting should be as follows:

First everything starting with 'Q%' keeping in mind that the integer after Q also plays a role (Q5 should be before Q6) etc.

Following is everything starting with 'L%', same logic as above. The 'W%' follow next and last are just the simple integers.

So what's the query and especially the ORDER BY part that I need to write? I tried the following which gives no errors but does not order the items in the order that I want and I can't figure out what's the logic behind it:

SELECT * FROM table
ORDER BY
  CASE type
    WHEN type LIKE 'Q%' THEN 1
    WHEN type LIKE 'L%' THEN 2
    WHEN type LIKE 'W%' THEN 3
    ELSE 4
  END,
  type ASC

I also tried with FIELD(...) but I don't think it takes into account something like 'Q%' at all although it doesn't give an error either nor it sorts them properly.

Any tips or ideas?

This should allow desired ordering.

ORDER BY FIELD(LEFT(type,1), 'Q', 'L', 'W')
   , CAST(type AS UNSIGNED)
   , CAST(SUBSTRING(type, 2) AS UNSIGNED)

The first one ensures those letters happen in that order; anything beginning otherwise will be ordered earlier. This is a benefit since you want pure numbers first, but may cause issues if there are other prefixes not accounted for.

The second makes sure the numeric strings order themselves numerically (so you won't get things like 1, 11, 12, 100, 2 . For strings beginning with letters this usually results in 0 (no sort); though it would position unaccounted for prefixes (if they exist) BEFORE most pure numbers.

The third part performs nearly identically to the second ordering, but is effective for the prefixed strings' numeric portions.

The second column should be sorted based on the integer value of the column:

SELECT `type`
FROM `table`
ORDER BY
    CASE 
        WHEN `type` LIKE 'Q%' THEN 1
        WHEN `type` LIKE 'L%' THEN 2
        WHEN `type` LIKE 'W%' THEN 3
        ELSE 4
    END,
    CASE 
        WHEN `type` LIKE 'Q%' THEN CONVERT(SUBSTRING(`type`, 2), SIGNED)
        WHEN `type` LIKE 'L%' THEN CONVERT(SUBSTRING(`type`, 2), SIGNED)
        WHEN `type` LIKE 'W%' THEN CONVERT(SUBSTRING(`type`, 2), SIGNED)
        ELSE CONVERT(`type`, SIGNED)
    END

SQL Fiddle

ok.. try this

This is if you do not want to see the manufactured order by field in the final answer..

select 

list-all-fields-here again-except the ordering field we derived...

from 
   (SELECT 
    CASE type
    WHEN type LIKE 'Q%' THEN 1
    WHEN type LIKE 'L%' THEN 2
    WHEN type LIKE 'W%' THEN 3
    ELSE 4
    END as MYORDERCOL,
    **list-all-fields-here vs a * **
    FROM table
 ) as tmp

 order by tmp.MYORDERCOL ASC

I generally avoid using * and always like to list out the explicit fields for clarity

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