Задавайте вопросы, мы ответим
Вы не зашли.
Здавствуйте форумчане. Поставлена следующая задача:
Дана таблица test вида
name rank
A 50
A 10
A 12
B 90
B 45
A 70
B 25
C 21
C 56
C 89
A 87
..............
Требуется вывести 10 лучших результатов по убыванию ранка, при этом значение столбца name должно повторяться максимум 2 раза, т.е. вполне может быть вид результата (вывод делать с первой буквы по алфавиту)
A | 87
A | 70
B | 90
...
То есть по-простому, нужно, чтобы выдавало для каждых 2-х одинаковых названий строки максимальный ранк
Все это нужно, чтобы реализовывалось в запросе без процедур и функций.
Заранее благодарю за помощь.
Отредактированно uNsLide (17.06.2010 01:16:55)
Неактивен
Если name бывает фиксированное количество штук, то можно сделать через UNION, в общем случае - нужно таки писать цикл.
Неактивен
Я думаю, что здесь все-таки через юнион нужно идти. Name пусть будет 20 штук, значение rank может быть любым абсолютно.
2 лимита будет.
Я нашел почти похожую тему - http://sqlinfo.ru/forum/viewtopic.php?id=577.
То есть построение запроса должно строиться так:
Сперва сделаем подзапроса на убывание ранга с лимитом в 2 записи, где ранг пренадлежит определенному name, а потом обьединение с запросом на выборку 10 названий каждого из name?
Или по-другому можно сделать? Например, как задать условие проверки следующей записи после какой-то по критерию?
Отредактированно uNsLide (17.06.2010 13:20:20)
Неактивен
Два лимита не будет — у Вас уже три значения у name в таблице.
А делать — да, именно так
(SELECT * FROM test WHERE name = 'A' ORDER BY rank DESC LIMIT 2)
UNION
(SELECT * FROM test WHERE name = 'B' ORDER BY rank DESC LIMIT 2)
…
Неактивен
Сейчас еще в голову пришел злобный хак: сначала выбрать максимальные
значения с группировкой по name, а потом выбрать максимальные значения
с группировкой по name и условием, что значение не равно тому, что нашли
в первом случае. Да, в этом случае первый подзапрос будет исполняться два
раза.
Неактивен
paulus написал:
Два лимита не будет — у Вас уже три значения у name в таблице.
А делать — да, именно так
(SELECT * FROM test WHERE name = 'A' ORDER BY rank DESC LIMIT 2)
UNION
(SELECT * FROM test WHERE name = 'B' ORDER BY rank DESC LIMIT 2)
…
(SELECT * FROM test WHERE name = 'A' ORDER BY rank DESC LIMIT 10)
UNION
(SELECT * FROM test WHERE name = 'B' ORDER BY rank DESC LIMIT 10)
Задали, чтобы показывало 10 записей каждого. Можно ли сюда еще как-то вставить ограничение, чтобы показывало только по 2 записи name или я пошел не в том направлении?
Неактивен
У меня там, кажется, стояло 2, а не 10 Тогда будет выводить как раз
по 2 записи на name.
Неактивен
Неактивен
paulus написал:
Сейчас еще в голову пришел злобный хак: сначала выбрать максимальные
значения с группировкой по name, а потом выбрать максимальные значения
с группировкой по name и условием, что значение не равно тому, что нашли
в первом случае. Да, в этом случае первый подзапрос будет исполняться два
раза.
А можно увидеть в виде кода данное сообщение?
Неактивен
Что-то такого типа, могу ошибаться:
SELECT * FROM (
(SELECT name, MAX(rank) AS rank
FROM test, (SELECT name, MAX(rank) AS rank FROM test GROUP BY name) s
WHERE NOT (test.name = s.name AND test.rank = s.rank)
GROUP BY name)
UNION
(SELECT name, MAX(rank) AS rank FROM test GROUP BY name)
) z ORDER BY name, rank DESC;
Неактивен
Рассматриваю первую часть до union с другими названиями аллиасов:
Неактивен
У Вас есть странная тенденция — делать запросы почти такими же, как пишу я,
но не такими же.
NOT ( a AND b ) = (NOT a) OR (NOT b) — вот правило булевой логики. А не то,
что Вы написали.
Неактивен
paulus написал:
У Вас есть странная тенденция — делать запросы почти такими же, как пишу я,
но не такими же.
NOT ( a AND b ) = (NOT a) OR (NOT b) — вот правило булевой логики. А не то,
что Вы написали.
Я понял, но результат остается такой же.
И правильно ли тогда обьединять запросы как я написал выше?
Неактивен
Они должны выдавать разные результаты — одно максимальное значение,
другое — второе сверху (т.к. максимальное мы исключаем через WHERE).
Неактивен
Если просто скопировать ваш запрос, то
#1248 - Every derived table must have its own alias
Отредактированно uNsLide (17.06.2010 16:30:12)
Неактивен
Я хотел, чтобы Вы идею поняли, а не копипастили
[celestia] root test > (SELECT test.name, MAX(test.rank) AS rank FROM test, (SELECT name, MAX(rank) AS rank FROM test GROUP BY name) s WHERE (test.name = s.name AND NOT test.rank = s.rank) GROUP BY name) UNION (SELECT name, MAX(rank) AS rank FROM test GROUP BY name) ORDER BY name, rank DESC; +------+------+ | name | rank | +------+------+ | A | 87 | | A | 50 | | B | 90 | | B | 45 | +------+------+ 4 rows in set (0.00 sec)
Неактивен
Я последние часы именно вникал в идею, копипастил в строку ввода запроса ,чтобы сперва проверить, что это работает, а затем изучал, что мы делаем.
Ошибки были выданы, используя mysql в комплекте денвер.
Из результата видно, что получили по 2 значения для А и B. А как же быть тогда, если есть строки с именами C,D,E... и их значениями, и требуется, чтобы их 10 выводило?
В mssql для этого вроде есть функция top, а тут только лимитами пользоваться или без них можно будет получить нужный результат?
Отредактированно uNsLide (17.06.2010 18:15:48)
Неактивен
Ну, если бы у меня были данные про C, то и С бы появилось — для того, чтобы
проверить работоспособность запроса мне хватило двух букв.
Про 10 букв Вы ничего не говорили изначально. Как простой хак — можете добавить
в WHERE условие name BETWEEN 'a' AND 'j'.
Неактивен
В самом первом моем сообщении данные про C были...
И 10 букв здесь не причем. 10 лучших записей по ранку по убыванию.
А вот и ошибка, из-за которой выдавались ошибки.
Отредактированно uNsLide (17.06.2010 18:50:55)
Неактивен