MySQL запрос - показать самый популярный элемент - PullRequest
2 голосов
/ 06 августа 2009

Мне нужно найти наиболее популярное вхождение элемента, сгруппированного по дате, и отобразить общее количество всех элементов вместе с названием этого элемента. Возможно ли что-то подобное в одном запросе?

примечание: если все они имеют одинаковое вхождение (см. Последние 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 ]

4 голосов
/ 07 августа 2009

Мое первоначальное предложение было неверно :

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 (*). Пожалуйста, сравните и посмотрите, подходит ли он для ваших нужд. Если нет, то я предлагаю получить ежедневные итоги в отдельном запросе. Вы объедините эти результаты в своем заявлении.

0 голосов
/ 07 августа 2009

Это как можно ближе ....

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 - это отображать только первый результат, который он находит за данную дату. Я не мог найти хороший способ произвольно выбрать один предмет, когда это был галстук. Надеюсь, это поможет.

0 голосов
/ 07 августа 2009

спасибо 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...