简体   繁体   中英

MySQL: Order by 2nd column--if not null--while maintaining 1st column order

Essentially I want to order by "title", while grouping movies with the same, non-NULL "series_id" together within that order. Titles where series_id IS NULL should order by title only, while non NULL series_ids should order by "series_order" and be listed in the results based on "series"."title" within the original columns sort. I would prefer to achieve this within the query rather then loading the entire database and sorting from there.

What I have tried (MySQL 5.7.17):

ORDER BY title, series_id

    SELECT * FROM media
        ORDER BY title, series_id, series_order
    LIMIT 0, 30

Does not account for titles in a series that are not alphabetically the same (see sample below).

ORDER BY CASE using CONCAT to sort by 'series'.'title' + 'media'.'series_order'

    SELECT * FROM media
        ORDER BY CASE
            WHEN series_id IS NULL THEN title
            ELSE CONCAT((SELECT title FROM series WHERE id = media.series_id), series_order)
        END
    LIMIT 0, 30

Th results are correctly ordered in a SQL Fiddle, but not on the dev server. To be fair this is still not the desired result as the 'series'.'title' may differ from the original movies title.

LEFT JOIN to include the 'series' table for sorting using the same idea

    SELECT media.*, series.title, series.id FROM media
        LEFT JOIN series ON media.series_id = series.id
    LIMIT 0, 30

This does not order the data correctly, either.

Sample Data :

title series_id series_order
88 Minutes NULL NULL
Live Free or Die Hard 100094 4
3rd Rock from the Sun 100000 2
2 Guns NULL NULL
Die Hard 100094 1
Evil Dead NULL NULL
A Good Day to Die Hard 100094 5
3rd Rock from the Sun 100000 1
Desired Result Order
2 Guns NULL
3rd Rock from the Sun 1
3rd Rock from the Sun 2
88 Minutes NULL
Die Hard 1
Live Free or Die Hard 4
A Good Day to Die Hard 5
Evil Dead NULL

Primary Table : media Relevant Columns : title, series_id, series_order

Series Table : series Relevant Columns : id, title

Fiddle : http://sqlfiddle.com/#!9/efca7c/3

On the fiddle, option 2 appears to be working. On the dev version it only partially orders things.

EDIT : As it turns out the PHP code I was using to store the data before converting it to JSON was inevitably re-ordering the results by the Primary ID.

Based on the required convolution to achieve your desired sorting, if this was my application, I'd probably create a new column which contains the "base title" for the series and populate that value during insertion, then you could sort on that without any voodoo or eye-strain.

In the absence of modifying your table structure, I managed to downgrade a solution that was using ROW_NUMBER() and PARTITION ( MySQL8.0 Demo ) into a couple of nested subqueries -- it's not what I consider beautiful.

SQL ( Demo )

SELECT m2.title grouping_title, m1.title, COALESCE(m2.title, m1.title), m1.series_order
FROM media m1
LEFT JOIN (
    SELECT series_id, title
    FROM media m3
    WHERE series_order = (SELECT MIN(series_order) FROM media WHERE series_id = m3.series_id)
) m2 ON m1.series_id = m2.series_id
ORDER BY COALESCE(m2.title, m1.title), m1.series_order

You can modify the outer SELECT as you wish, but I just wanted to show what the COALESCE() function was generating. Effectively, I'm joining media table onto itself so that I can obtain the lowest series_order value for a given series_id . The title in the THAT row represents the "base title" to be used in the first rule of the sorting algorithm -- unless it is NULL , in which case, we just use the title from the parent query.

For your application output, you will want to use the m1.title and the m1.series_order .

Use a CASE expression to check whether seris_order value is null, if it is null then take only titlw, otherwise concatenate title with the series_order.

Query

Select case when series_order is null then title else concat(title, ' : Season ', series_order) end as title
From table_name
Order by 1;

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