我有一个Intranet网站,只有注册用户才能观看视频。用户可以在iPhone,iPad,Android或Web等多个平台上观看视频,并跟踪所有这些信息(为了简化问题,请不要考虑其他平台)。我想在管理员面板上显示一些视频观看报告。
表结构如下(我有很多其他列,但它们对于这个问题并不重要);
CREATE TABLE IF NOT EXISTS `history` (
`history_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`video_id` int(11) unsigned NOT NULL,
`user_id` int(11) unsigned NOT NULL,
`platform_id` int(11) unsigned NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`history_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=9 ;
INSERT INTO `history` (`history_id`, `video_id`, `user_id`, `platform_id`, `created`) VALUES
(1, 1, 1, 1, '2012-05-06 08:13:57'),
(2, 2, 1, 1, '2012-05-06 13:23:57'),
(3, 1, 1, 4, '2012-05-06 18:16:39'),
(4, 4, 2, 3, '2012-05-07 08:14:19'),
(5, 1, 2, 3, '2012-05-07 08:14:55'),
(6, 2, 1, 1, '2012-05-07 15:14:55'),
(7, 3, 2, 1, '2012-05-07 18:05:14'),
(8, 3, 1, 4, '2012-05-07 18:15:24');
CREATE TABLE IF NOT EXISTS `sys_list_of_values` (
`value_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`display_text` text COLLATE utf8_unicode_ci NOT NULL,
`list_value` text COLLATE utf8_unicode_ci NOT NULL,
`list_group` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`value_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10 ;
INSERT INTO `sys_list_of_values` (`value_id`, `display_text`, `list_value`, `list_group`) VALUES
(1, 'iPhone', 'iphone', 'platform'),
(2, 'Android', 'android', 'platform'),
(3, 'iPad', 'ipad', 'platform'),
(4, 'Website', 'web', 'platform'),
(5, 'Active', 'active', 'status'),
(6, 'Passive', 'passive', 'status'),
(7, 'Waiting for approvement', 'waiting', 'status'),
(8, 'Spam', 'spam', 'status'),
(9, 'Deleted', 'deleted', 'status');
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;
INSERT INTO `users` (`user_id`, `username`) VALUES
(1, 'test_user_1'),
(2, 'test_user_2');
CREATE TABLE IF NOT EXISTS `videos` (
`video_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL,
`title` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`status` int(11) unsigned NOT NULL,
PRIMARY KEY (`video_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=5 ;
INSERT INTO `videos` (`video_id`, `user_id`, `title`, `created`, `status`) VALUES
(1, 1, 'Test Video 1', '2012-05-07 08:12:52', 7),
(2, 1, 'Test Video 2', '2012-05-07 08:12:52', 5),
(3, 1, 'Test Video 3', '2012-05-07 08:13:17', 5),
(4, 1, 'Test Video 4', '2012-05-07 08:13:17', 6);
我正在尝试显示如下的报告;
Platform | Watch_Count
===============================
iPhone 20
iPad 0
Android 2
Website 120
Total 142
我有一些过滤器选项,例如video_id
,created
,platform
等。例如;我想显示所有视频,特定视频(video_id)或日期(已创建)等的总观看报告。我还想显示所有平台,无论它们是0还是其他任何平台。
以下查询仅显示iPhone和网站,但我想显示所有平台。如果没有手表计数,则必须显示为0(零)。我也无法显示汇总所有watch_count
的最后一行并显示总数。
SELECT sys_list_of_values.display_text, COUNT(history.history_id) AS 'total_watch' FROM history
JOIN sys_list_of_values ON sys_list_of_values.value_id = history.platform_id
WHERE history.video_id = 1
AND history.created < '2012-05-07'
GROUP BY history.platform_id
答案 0 :(得分:3)
保留FROM HISTORY
,将JOIN
更改为RIGHT JOIN
SELECT sys_list_of_values.display_text, COUNT(history.history_id) AS 'total_watch'
FROM history
RIGHT JOIN sys_list_of_values
ON sys_list_of_values.value_id = history.platform_id
AND history.created < '2012-05-07'
AND history.video_id = 1
GROUP BY sys_list_of_values.value_id
order by sys_list_of_values.display_text;
如果您想使用LEFT JOIN
,请切换历史记录和sys_list_of_values:
SELECT sys_list_of_values.display_text, COUNT(history.history_id) AS 'total_watch'
FROM sys_list_of_values
LEFT JOIN history
ON sys_list_of_values.value_id = history.platform_id
AND history.created < '2012-05-07'
AND history.video_id = 1
GROUP BY sys_list_of_values.value_id
order by sys_list_of_values.display_text;
实时测试:http://www.sqlfiddle.com/#!2/495d1/15
GROUP BY与ROLLUP与ORDER不兼容,无论如何ROLLUP会自动对列表进行排序,只需删除ORDER:
SELECT sys_list_of_values.display_text,
-- sys_list_of_values.value_id,
COUNT(history.platform_id) AS 'total_watch'
FROM sys_list_of_values
LEFT JOIN history
ON sys_list_of_values.value_id = history.platform_id
AND history.created < '2012-05-07'
AND history.video_id = 1
where sys_list_of_values.list_group = 'platform'
GROUP BY
sys_list_of_values.display_text with rollup
答案 1 :(得分:0)
使用LEFT JOIN
并将涉及“正确”表格的条件从WHERE
移至ON
:
SELECT s.display_text
, COUNT(h.history_id) AS total_watch
FROM
sys_list_of_values AS s
LEFT JOIN
history AS h
ON h.platform_id = s.value_id
AND h.video_id = 1
AND h.created < '2012-05-07'
GROUP BY s.value_id
WITH ROLLUP --- for an additional final row with total sum
如果您需要ORDER BY display_text
和ROLLUP
,请使用此选项:
GROUP BY s.display_text
WITH ROLLUP
答案 2 :(得分:0)
您可以使用子查询将计数加入平台列表:
SELECT display_text, IFNULL(total_watch, 0)
FROM sys_list_of_values
LEFT JOIN (
SELECT platform_id AS value_id, COUNT(history_id) AS total_watch
FROM history
WHERE video_id = 1
AND history.created < '2012-05-07'
GROUP BY platform_id
) AS watch_counts USING (value_id)
WHERE list_group = 'platform'
顺便说一下,在应用程序代码中完成平台列表而不是在数据库中执行它通常更有效率,特别是如果假设应用程序代码具有所有现有平台的长期缓存。 / p>
答案 3 :(得分:0)
SELECT
sys_list_of_values.value_id as VID,
sys_list_of_values.display_text,
COUNT(history.history_id) AS 'total_watch'
FROM sys_list_of_values
JOIN history
ON sys_list_of_values.value_id = history.platform_id
where sys_list_of_values.list_group = 'platform'
and history.created < '2012-05-07'
GROUP BY history.platform_id
order by VID