skip to Main Content

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.

2

Answers


  1. 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;
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search