phpmysqldatabasemovies

Group Movie Sessions By Dates


My movie database allows users to enter database into a sessions table which looks like this:

id | time | movie_id

Where time is the datetime the movie will be played and movie_id is a key relating to the movies table.

Now, I am trying to find consecutive days where the movies being played are the same. For example I want to be able to display.

3/6/2013 - 7/6/2013
Iron Man 3   7pm
Second Movie 10pm
ETC...

8/6/2013
Iron Man 3   8pm

9/6/2013 - 11/6/2013
Iron Man 3   7pm
Second Movie 10pm

Is there anyway to group using both the time and finding the consecutive days? I could change the table to a seperate date and time value if needed. Any help would be much appreciated. If this is only achievable in PHP, any idea on how to get started would also be appreciated.

Thank you. If you have any questions or this question isnt clear enough please ask.


Solution

  • Well, not so elegant, but working solution using GROUP_CONCAT aggregate function and variables within SELECT to groups similar consecutive days.

    Your schema and example data set:

    CREATE TABLE movies (
      id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      title CHAR(64) NOT NULL
    );
    CREATE TABLE schedule (
      id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      time TIMESTAMP NOT NULL,
      movie_id INT NOT NULL
    );
    INSERT INTO movies (title) VALUES
      ('Iron Man 3'),
      ('Second Movie')
    ;
    INSERT INTO schedule (time, movie_id) VALUES
      ('2013-06-03 19:00:00', 1),
      ('2013-06-03 22:00:00', 2),
      ('2013-06-04 19:00:00', 1),
      ('2013-06-04 22:00:00', 2),
      ('2013-06-05 19:00:00', 1),
      ('2013-06-05 22:00:00', 2),
      ('2013-06-06 19:00:00', 1),
      ('2013-06-06 22:00:00', 2),
      ('2013-06-07 19:00:00', 1),
      ('2013-06-07 22:00:00', 2),
      ('2013-06-08 20:00:00', 1),
      ('2013-06-09 19:00:00', 1),
      ('2013-06-09 22:00:00', 2),
      ('2013-06-10 19:00:00', 1),
      ('2013-06-10 22:00:00', 2),
      ('2013-06-11 19:00:00', 1),
      ('2013-06-11 22:00:00', 2),
      ('2013-06-13 19:00:00', 1),
      ('2013-06-13 22:00:00', 2)
    ;
    

    The query:

    SELECT
        DATE_FORMAT(min_date, '%e/%c/%Y') AS beg_date,
        DATE_FORMAT(max_date, '%e/%c/%Y') AS end_date,
        title,
        LOWER(TIME_FORMAT(time, '%l%p')) AS `movie_time`
      FROM
        (SELECT
            MIN(min_date) AS min_date,
            MAX(max_date) AS max_date,
            range_schedule
          FROM
            (SELECT
                @min_date :=
                  IF(@range_schedule <=> day_schedule
                     AND days.date <=> ADDDATE(@max_date, 1),
                    @min_date,
                    days.date
                  ) AS min_date,
                @max_date := days.date AS max_date,
                @range_schedule := days.day_schedule AS range_schedule
              FROM
                (
                  SELECT DATE(time) AS `date`, GROUP_CONCAT(CONCAT(TIME(time), '-', movie_id) ORDER BY time) AS day_schedule
                  FROM schedule
                  GROUP BY DATE(time)
                  ORDER BY DATE(time)
                ) AS days,
                (SELECT
                  @min_date := '0000-00-00',
                  @max_date := '0000-00-00',
                  @range_schedule := NULL
                ) r
            ) days_of_ranges
          GROUP BY min_date, range_schedule
        ) ranges
        JOIN schedule ON DATE(schedule.time) = ranges.min_date
        JOIN movies ON movies.id = movie_id
      ORDER BY min_date, time
    ;
    

    And the result:

    |  BEG_DATE |  END_DATE |        TITLE | MOVIE_TIME |
    -----------------------------------------------------
    |  3/6/2013 |  7/6/2013 |   Iron Man 3 |        7pm |
    |  3/6/2013 |  7/6/2013 | Second Movie |       10pm |
    |  8/6/2013 |  8/6/2013 |   Iron Man 3 |        8pm |
    |  9/6/2013 | 11/6/2013 |   Iron Man 3 |        7pm |
    |  9/6/2013 | 11/6/2013 | Second Movie |       10pm |
    | 13/6/2013 | 13/6/2013 |   Iron Man 3 |        7pm |
    | 13/6/2013 | 13/6/2013 | Second Movie |       10pm |
    

    All that you need to do in PHP is to store last BEG_DATE and END_DATE values to compare them with current ones to decide when to output range header.