Reputation: 185
Each row represents a video that was on air at particular time on particular date. There are about 1600 videos per day.
CREATE TABLE `air_video` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`date` DATE NOT NULL,
`time` TIME NOT NULL,
`duration` TIME NOT NULL,
`asset_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(100) NOT NULL,
`status` VARCHAR(100) NULL DEFAULT NULL,
`updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `date_2` (`date`, `time`),
INDEX `date` (`date`),
INDEX `status` (`status`),
INDEX `asset_id` (`asset_id`)
)
ENGINE=InnoDB
There are two conditions.
In rotation means time span between the fist and the last time the video was on air.
So I need to select all videos that violate those conditions, given user-specified date range.
The result must be grouped by day and by asset_id (video id). For example:
date asset_id name dailyCount rotationSpan
2012-04-27 123 whatever_the_name 35 76
2012-04-27 134 whatever_the_name2 39 20
2012-04-28 125 whatever_the_name3 26 43
By now I have written this query:
SELECT
t1.date, t1.asset_id, t1.name,
(SELECT
COUNT(t3.asset_id)
FROM air_video AS t3
WHERE t2.asset_id = t3.asset_id AND t3.date = t1.date
) AS 'dailyCount',
MIN(CONCAT(t2.date, ' ', t2.time)) AS 'firstAir',
MAX(CONCAT(t2.date, ' ', t2.time)) AS 'lastAir',
ROUND(TIMESTAMPDIFF(
MINUTE,
MIN(CONCAT(t2.date, ' ', t2.time)),
MAX(CONCAT(t2.date, ' ', t2.time))
) / 60) as 'rotationSpan'
FROM
air_video AS t1
INNER JOIN
air_video AS t2 ON
t1.asset_id = t2.asset_id
WHERE
t1.status NOT IN ('bumpers', 'clock', 'weather')
AND t1.date BETWEEN '2012-04-01' AND '2012-04-30'
GROUP BY
t1.asset_id, t1.date
HAVING
`rotationSpan` > 72
OR `dailyCount` > 24
ORDER BY
`date` ASC,
`rotationSpan` DESC,
`dailyCount` DESC
lastAir
timestamp is not the latest time the video was aired on particular date but the latest time it was on air altogether.Upvotes: 4
Views: 149
Reputation: 951
If you need to speed up your query you need to remove the select sub query on line 3. To still have that count you can inner join it again in the from clause with the exact parameters you used initially. This is how it should look:
SELECT
t1.date, t1.asset_id, t1.name,
COUNT(t3.asset_id) AS 'dailyCount',
MIN(CONCAT(t2.date, ' ', t2.time)) AS 'firstAir',
MAX(CONCAT(t2.date, ' ', t2.time)) AS 'lastAir',
ROUND(TIMESTAMPDIFF(
MINUTE,
MIN(CONCAT(t2.date, ' ', t2.time)),
MAX(CONCAT(t2.date, ' ', t2.time))
) / 60) as 'rotationSpan'
FROM
air_video AS t1
INNER JOIN
air_video AS t2 ON
(t1.asset_id = t2.asset_id)
INNER JOIN
air_video AS t3
ON (t2.asset_id = t3.asset_id AND t3.date = t1.date)
WHERE
t1.status NOT IN ('bumpers', 'clock', 'weather')
AND t1.date BETWEEN '2012-04-01' AND '2012-04-30'
GROUP BY
t1.asset_id, t1.date
HAVING
`rotationSpan` > 72
OR `dailyCount` > 24
ORDER BY
`date` ASC,
`rotationSpan` DESC,
`dailyCount` DESC
Since t2 is not bound by date, you are obviously looking at the whole table, instead of the date range.
Edit: Due to a lot of date bindings the query still ran too slowly. I then took a different approach. I created 3 views (which you obviously can combine into a normal query without the views, but I like the end result query better)
--T1--
CREATE VIEW t1 AS select date,asset_id,name from air_video where (status not in ('bumpers','clock','weather')) group by asset_id,date order by date;
--T2--
CREATE VIEW t2 AS select t1.date,t1.asset_id,t1.name,min(concat(t2.date,' ',t2.time)) AS 'firstAir',max(concat(t2.date,' ',t2.time)) AS 'lastAir',round((timestampdiff(MINUTE,min(concat(t2.date,' ',t2.time)),max(concat(t2.date,' ',t2.time))) / 60),0) AS 'rotationSpan' from (t1 join air_video t2 on((t1.asset_id = t2.asset_id))) group by t1.asset_id,t1.date;
--T3--
CREATE VIEW t3 AS select t2.date,t2.asset_id,t2.name,count(t3.asset_id) AS 'dailyCount',t2.firstAir,t2.lastAir,t2.rotationSpan AS rotationSpan from (t2 join air_video t3 on(((t2.asset_id = t3.asset_id) and (t3.date = t2.date)))) group by t2.asset_id,t2.date;
From there you can then just run the following query:
SELECT
date,
asset_id,
name,
dailyCount,
firstAir,
lastAir,
rotationSpan
FROM
t3
WHERE
date BETWEEN '2012-04-01' AND '2012-04-30'
AND (
rotationSpan > 72
OR
dailyCount > 24
)
ORDER BY
date ASC,
rotationSpan DESC,
dailyCount DESC
Upvotes: 3