0

I have a table, containing TV series episodes:

 series:
    | series_id | season | episode | title
    |         1 |      1 |      18 | xxx
    |         1 |      2 |       3 | xxy
    |         3 |      1 |      13 | yyy
    |         3 |      2 |       5 | yyy   

I want to get the latest episode from each show, so 2x03 from series 1, and 2x05 from series 3.

I have 3 ideas, none of them great:

  1. Create a new integer column, calculated as season x 100 + episode, now I can sort easily by it, and quite fast, but I have to recalculate it every time if the season or episode column is updated.

  2. Write a select that first finds the max(season) for each series, and use it in a second select. Easier to maintain, but I was not able to write the right sql statement yet.

  3. Use a calculated aggregare:

    SELECT series_id, max( 100* season + episodes ) as latest FROM series GROUP BY series_id;

Which option is better? How should I write option 2?

6
  • What is the primary key of the table? Apr 9, 2014 at 11:33
  • If this is an OLTP app, don't store derived information -- unless it's absolutely performance critical. So I'd much prefer option 2 over option 1. Apr 9, 2014 at 11:44
  • @Colin'tHart SQLite does not have analytic or window functions. Apr 9, 2014 at 11:45
  • @Colin'tHart: thanks, I did not know that. I expect the calculated column to be very rarely updated, so option 1 seems fine.
    – András
    Apr 9, 2014 at 11:48
  • Then I hope you're only inserting into or updating this table in one place in your code. Apr 9, 2014 at 11:50

1 Answer 1

1

It can be done with a query:

SELECT 
    s.*
FROM
  ( SELECT DISTINCT series_id
    FROM series
  ) AS ds
  JOIN
    series AS s
      ON  s.series_id = ds.series_id
      AND s.season =
          ( SELECT si.season
            FROM series AS si
            WHERE si.series_id = ds.series_id
            ORDER BY si.season DESC
            LIMIT 1
          ) 
      AND s.episode =
          ( SELECT si.episode
            FROM series AS si
            WHERE si.series_id = ds.series_id
            ORDER BY si.season DESC, si.episode DESC
            LIMIT 1
          ) ;

Tested at SQL-Fiddle

With an index on (series_id, season, episode), it should be quite efficient, if the number of series_id is small.

CREATE UNIQUE INDEX uix
  ON series
  (series_id, season, episode) ;

There are several ways to do this query but all get rather complicated because the maximum needed is based on two columns (season and episode). Here's another one, which is the query above, simplified a bit:

SELECT 
    s.*
FROM
  ( SELECT series_id, MAX(season) AS season
    FROM series
    GROUP BY series_id
  ) AS ds
  JOIN
    series AS s
      ON  s.series_id = ds.series_id
      AND s.season = ds.season
      AND s.episode =
          ( SELECT si.episode
            FROM series AS si
            WHERE si.series_id = ds.series_id
              AND si.season = ds.season
            ORDER BY si.episode DESC
            LIMIT 1
          ) ;

and another using NOT EXISTS:

SELECT s.*
FROM series AS s
WHERE NOT EXISTS
      ( SELECT 1
        FROM series AS sb
        WHERE sb.series_id = s.series_id
          AND ( sb.season > s.season
             OR sb.season = s.season AND sb.episode > s.episode
              )
      ) ;
6
  • Thanks. This looks even more complicated, than I imagined.
    – András
    Apr 9, 2014 at 11:30
  • What about option 1? When is it better?
    – András
    Apr 9, 2014 at 11:31
  • Having another column that you base the query should be more efficient. But you have the extra cost of maintaining it. There is no way to tell what would be best in your situation, than testing. Apr 9, 2014 at 11:33
  • SELECT series_id, max( 100* season + episodes ) as latest FROM series GROUP BY series_id;
    – András
    Apr 9, 2014 at 12:35
  • Is this not easier?
    – András
    Apr 9, 2014 at 12:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.