mySQL查询 - 显示最受欢迎的项目

时间:2009-08-06 19:56:11

标签: php mysql

我需要查找按日期分组的项目中最常见的事件,并显示所有项目的总数以及此项目的名称。在单个查询中是否可以这样?

注意:如果它们全部相同(参见插入中的最后3行),我可以随机显示或第一次或最后一次出现(以最简单的方式)。

如果在sql中无法做到这一点,则必须运行结果并通过PHP对数据进行排序,这看起来很混乱。

编辑:对不起,'2009 '08-04'的错误总数。它应该是4。

我需要的一个例子:

+------------+---------------------+-------+
| date       | item                | total |
+------------+---------------------+-------+
| 2009-08-02 | Apple               |     5 |
| 2009-08-03 | Pear                |     2 |
| 2009-08-04 | Peach               |     4 |
| 2009-08-05 | Apple               |     1 |
| 2009-08-06 | Apple               |     3 |
+------------+---------------------+-------+

这是一个示例表:

CREATE TABLE IF NOT EXISTS `test_popularity` (
  `date` datetime NOT NULL,
  `item` varchar(256) NOT NULL,
  `item_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `test_popularity` (`date`, `item`, `item_id`) VALUES
('2009-08-02 00:00:00', 'Apple', 1),
('2009-08-02 00:00:00', 'Pear', 3),
('2009-08-02 00:00:00', 'Apple', 1),
('2009-08-02 00:00:00', 'Apple', 1),
('2009-08-02 00:00:00', 'Pear', 0),
('2009-08-03 00:00:00', 'Pear', 3),
('2009-08-03 00:00:00', 'Peach', 2),
('2009-08-04 00:00:00', 'Apple', 1),
('2009-08-04 00:00:00', 'Peach', 2),
('2009-08-04 00:00:00', 'Peach', 2),
('2009-08-04 00:00:00', 'Pear', 3),
('2009-08-05 00:00:00', 'Apple', 1),
('2009-08-06 00:00:00', 'Apple', 1),
('2009-08-06 00:00:00', 'Peach', 2),
('2009-08-06 00:00:00', 'Pear', 3);

3 个答案:

答案 0 :(得分:4)

我的初步建议不正确

SELECT
  date, item, SUM(cnt)
FROM (
  SELECT
    date, item, count(item_id) AS cnt
  FROM test_popularity
  GROUP BY date, item_id
  ORDER BY cnt DESC
) t
GROUP BY date;

这错误地假设外部聚合(按日期)将选择由cnt排序的内部派生表的第一行。事实上,这种行为是未定义的,并且不能保证一致。

这是正确的解决方案:

SELECT
  t1.date, t1.item, 
  (SELECT COUNT(*) FROM test_popularity WHERE date = t1.date) as total
  # see note!
FROM test_popularity t1
JOIN (
  SELECT date, item, item_id, COUNT(item_id) as count
  FROM test_popularity
  GROUP BY date, item_id
) AS t2
ON t1.date = t2.date AND t1.item_id = t2.item_id
GROUP BY t1.date;

注意:

我添加了(SELECT COUNT(*)) AS total,因为在一个查询中提出了这个问题。但是,这不会缩放,因为它是相关的子查询。这意味着对于每个t1.date,SELECT COUNT(*)子查询将运行。请进行基准测试,看看它是否适合您的需求。如果没有,那么我建议在单独的查询中获取每日总计。您可以在应用程序中合并这些结果。

答案 1 :(得分:0)

感谢hohodave最初的回应:

SELECT date, item, cnt, (
SELECT COUNT( * )
FROM test_popularity
WHERE date = t.date
) AS totalCnt
FROM (
SELECT date, item, count( item_id ) AS cnt
FROM test_popularity
GROUP BY date, item_id
ORDER BY cnt DESC
)t
GROUP BY date;

答案 2 :(得分:0)

这是我能得到的尽可能接近......

SELECT DISTINCT p.date, ItemTotalsByDate.Item, DateTotals.Total
    FROM test_popularity p
    INNER JOIN 
(SELECT date, MAX(cnt) DayMax from
(SELECT date, item, COUNT(*) cnt
FROM dbo.test_popularity
GROUP BY date, item) tbl
GROUP BY date) MaxesByDate
    ON p. date = MaxesByDate.date
INNER JOIN 
(SELECT date, item, COUNT(*) Total FROM dbo.test_popularity
GROUP BY date, item) ItemTotalsByDate
    ON MaxesByDate.date = ItemTotalsByDate.date AND MaxesByDate.DayMax = ItemTotalsByDate.Total
INNER JOIN
(SELECT date, COUNT(*) Total FROM dbo.test_popularity
GROUP BY date) DateTotals
ON p.date = DateTotals.date

这给PHP留下的唯一事情就是只显示它为给定日期找到的第一个结果。我无法想出一个好的方法,当它是一个领带时随意选择一个项目。希望这会有所帮助。