выборка максимальных элементов массива

Lifeline

Новичок
выборка максимальных элементов массива

После НГ очень сложно соображать :) Хелп :)

Есть таблица

article_id
category_id
views


надо выбрать наиболее популярные статьи в каждой категории

делаю так

select article_id, category_id, max(views) as max_views from articles group by category_id

выдает максимальные просмотры по категориям, но ИД статей неверные.
Те условно категория 1, кол-во просмотров 100 ( это все верно), но ИД статьи не верный.


Что я делаю не так?
 

Lifeline

Новичок
RUNET, если не группировать то оно ж выдаст вообще 1 только статью.
 

phprus

Moderator
Команда форума
Может помочь такой запрос:
Код:
SELECT a.article_id, a.поля_по_вкусу FROM articles a
JOIN ( SELECT category_id, max(views) AS max_views FROM articles GROUP BY category_id ) v ON (a.category_id = v.category_id)
WHERE a.views = v.max_views
Правда есть подозрение, что через два запроса это будет работать быстрее. Можно еще сделать через аналитические функции, но в MySQL их поддержки нету.
 

Lifeline

Новичок
phprus спасибо, такой вариант работает, хотя конечно explain запроса выглядит угрожающе :)
 

prolis

Новичок
это работает до тех пор, пока у нескольких статей одной категории не будет одинаковое количество просмотров
 

phprus

Moderator
Команда форума
prolis
В ТЗ сказано, что надо выбрать "наиболее популярные статьи", а не "наиболее популярную статью". Тоесть я думаю, что допустимо выбрать несколько статей если они с одинаковой популярностью.

А вот как решить задачу, если нужно выбрать только одну статью (любую или по какому-либо критерию), в случае наличия нескольких статей в категории с одинаковой популярностью, средствами MySQL я так сходу не знаю.
 

Lifeline

Новичок
несколько статей с одинаковым кол-вом просомтров это не так страшно как explain этого запроса.

надо отдельно оттестить на более менее приличной базе.
 

Lifeline

Новичок
Таблица

CREATE TABLE IF NOT EXISTS `articles` (
`article_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category_id` int(10) unsigned NOT NULL,
`views` int(10) unsigned NOT NULL,
PRIMARY KEY (`article_id`)
) ENGINE=MyISAM


запрос


EXPLAIN SELECT a.article_id, a.views
FROM articles AS a
JOIN (
SELECT category_id, max( views ) AS max_views
FROM articles
GROUP BY category_id
) AS v ON ( a.category_id = v.category_id )
WHERE a.views = v.max_views


результат


1 PRIMARY <derived2> ALL NULL NULL NULL NULL 71
1 PRIMARY a ALL NULL NULL NULL NULL 10000 Using where; Using join buffer
2 DERIVED articles ALL NULL NULL NULL NULL 10000 Using temporary; Using filesort
 

Gas

может по одной?
alter table articles add index ctg_views(category_id, views);

как теперь explain ?
 

Gas

может по одной?
Индекс на category_id здесь очевиден, мне интересна только строка из explain'а для DERIVED запроса, появилась там строка "Using index for group-by" вместо "Using temporary; Using filesort" или нет.
 

Lifeline

Новичок
да


1 PRIMARY <derived2> ALL NULL NULL NULL NULL 71
1 PRIMARY a ref ctg_views ctg_views 8 v.category_id,v.max_views 1
2 DERIVED articles range NULL ctg_views 4 NULL 71 Using index for group-by
 

Lifeline

Новичок
Дабы не плодить новые темы , спрошу тут :)

Та же таблица

article_id
category_id
views

НО к каждой статье есть таги.

Задача: выбрать наиболее популярные статьи относительно текущей. Те человек зашел почитать про пхп, а мы ему советуем мол посмотрите еще вот эти статьи по теме.

Выбирать предполагается по тагам. Те найти статьи с похожими тагами и выбрать из них Х наиболее популярных.


Варианта 1.

article_id
category_id
views
tags - таги разделенные запятыми


Вариант 2. вынос тагов в отдельную таблицу

tag_id
tag

+ таблица соответствий

article_id
tag_id



Вопрос: в какую сторону лучше копать :)
 

Lifeline

Новичок
Gas почти персональная переписка уже :)

Та же проблема

3 таблицы

статьи

article_id
category_id
views


таги
tag_id
tag


соответствия
article_id
tag_id


надо выбрать наиболее популярные статьи для указанного тага.

В идеале конечно больше чем для одного тага (группы тагов), тк у текущей статьи может быть больше одного тага - надо найти наиболее популярные статьи по каждому из тагов.


Делаю JOIN но через 3 таблицы он у меня страшно тормозит и нет уверенности что он находит то что надо :)
 

phprus

Moderator
Команда форума
Lifeline
Покажи запрос и его explain.
Тут запрос будет аналогичный, как для популярности по категориям, но он судя по всему медленный. Я могу предложить не считать эту выборку каждый раз, а кешировать ее и пересчитывать, к примеру, раз в Х единиц времени.
 

Gas

может по одной?
В идеале конечно больше чем для одного тага (группы тагов),
как-то проблемы я не вижу, ты вытянул статью и её теги, у тебя уже есть id-шники тегов, делается

select article_id, count(*) as cnt from `соответствия` where tag_id in (id1, id2, ...) group by article_id order by cnt desc limit 10

- вот у тебя id статей, которые больше всего связаны с нужными тегами. Чтоб достать сами все статьи, можно к этому запросу приджойнить таблицу `статьи`. Но я бы сделал так:

select * from `статьи` join (select ...мой предыдущий запрос...) as t on t.article_id = `статьи`.article_id

А вообще, как и сказал phprus, покажи что ты делаешь и explain
 
Сверху