0

我有一个只有注册用户才能观看视频的 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,createdplatform。例如;我想显示所有视频、特定视频(video_id)或日期之间(创建)等的总观看报告。我还想显示所有平台,无论它们是 0 还是其他任何东西。

以下查询仅显示 iPhone 和网站,但我想显示所有平台。如果没有观察计数,则必须显示为 0(零)。我也无法显示对所有watch_counts 求和并显示总数的最后一行。

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
4

4 回答 4

3

保留你的FROM HISTORY,改变你JOINRIGHT 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 with 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

现场测试:http ://www.sqlfiddle.com/#!2/495d1/68

于 2012-05-07T11:54:40.733 回答
0

使用LEFT JOIN并将涉及“正确”表的条件从 移动WHEREON

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_textand ROLLUP,使用这个:

GROUP BY s.display_text
  WITH ROLLUP             
于 2012-05-07T11:47:15.487 回答
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'

顺便说一句,在应用程序代码中完成平台列表通常比在数据库中完成更高效,特别是如果假设应用程序代码拥有所有现有平台的长期缓存。

于 2012-05-07T11:49:02.633 回答
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
于 2012-05-07T12:05:16.000 回答