SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 17.06.2010 01:14:08

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Запрос на вывод 10 лучших результатов

Здавствуйте форумчане. Поставлена следующая задача:
Дана таблица 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)

Неактивен

 

#2 17.06.2010 08:54:52

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

Если name бывает фиксированное количество штук, то можно сделать через UNION, в общем случае - нужно таки писать цикл.

Неактивен

 

#3 17.06.2010 13:19:29

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

Я думаю, что здесь все-таки через юнион нужно идти. Name пусть будет 20 штук, значение rank может быть любым абсолютно.
2 лимита будет.

Я нашел почти похожую тему - http://sqlinfo.ru/forum/viewtopic.php?id=577.
То есть построение запроса должно строиться так:
Сперва сделаем подзапроса на убывание ранга с лимитом в 2 записи, где ранг пренадлежит определенному name, а потом обьединение с запросом на выборку 10 названий каждого из name?

Или по-другому можно сделать? Например, как задать условие проверки следующей записи после какой-то по критерию?

Отредактированно uNsLide (17.06.2010 13:20:20)

Неактивен

 

#4 17.06.2010 13:28:11

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

Два лимита не будет — у Вас уже три значения у 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)

Неактивен

 

#5 17.06.2010 13:31:42

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

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

Неактивен

 

#6 17.06.2010 13:47:09

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

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 или я пошел не в том направлении?

Неактивен

 

#7 17.06.2010 13:54:22

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

У меня там, кажется, стояло 2, а не 10 wink Тогда будет выводить как раз
по 2 записи на name.

Неактивен

 

#8 17.06.2010 14:15:40

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

SELECT name,rank FROM test
WHERE rank IN
  (SELECT rank FROM test WHERE name = 'A')  
ORDER BY rank DESC
LIMIT 2

Вот мы получили 2 значения ранка по убыванию для name А. Теперь ставим условие, что значение не равно тому, что нашли
в первом случае ?

Неактивен

 

#9 17.06.2010 14:39:06

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

paulus написал:

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

А можно увидеть в виде кода данное сообщение?

Неактивен

 

#10 17.06.2010 15:01:16

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

Что-то такого типа, могу ошибаться:

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;

Неактивен

 

#11 17.06.2010 15:43:08

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

Рассматриваю первую часть до union с другими названиями аллиасов:

SELECT name, MAX(rank) AS rank
FROM test, (SELECT name as id, MAX(rank) AS m FROM test GROUP BY id) as s
WHERE (test.name <> s.id AND test.rank <> s.m)
GROUP BY name

Этот запрос выдает
name    rank
A    87
B    90
C    89
Запрос после union выдает тот же самый результат.
Запрос вида
SELECT * FROM (
(SELECT name, MAX(rank) AS rank FROM test GROUP BY name)as z)
order by name, rank desc
выдает такой же результат
То есть получается мы выводим все из (А 87 B 90 ...), обьединяем с этим же и сортируем по названию и убывающему ранку. Так ли стоить обьединять?
Может правильнее будет обьединить первую часть с элементами, у которых ранк меньше max и limit 1?

Неактивен

 

#12 17.06.2010 15:48:21

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

У Вас есть странная тенденция — делать запросы почти такими же, как пишу я,
но не такими же.

NOT ( a AND b ) = (NOT a) OR (NOT b)   — вот правило булевой логики. А не то,
что Вы написали.

Неактивен

 

#13 17.06.2010 15:59:04

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

paulus написал:

У Вас есть странная тенденция — делать запросы почти такими же, как пишу я,
но не такими же.

NOT ( a AND b ) = (NOT a) OR (NOT b)   — вот правило булевой логики. А не то,
что Вы написали.

Я понял, но результат остается такой же.
И правильно ли тогда обьединять запросы как я написал выше?

Неактивен

 

#14 17.06.2010 16:20:46

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

Они должны выдавать разные результаты — одно максимальное значение,
другое — второе сверху (т.к. максимальное мы исключаем через WHERE).

Неактивен

 

#15 17.06.2010 16:27:25

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

Если просто скопировать ваш запрос, то
#1248 - Every derived table must have its own alias


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
 

Тут #1052 - Column 'name' in field list is ambiguous

Отредактированно uNsLide (17.06.2010 16:30:12)

Неактивен

 

#16 17.06.2010 18:09:01

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

Я хотел, чтобы Вы идею поняли, а не копипастили wink

Код:

[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)

Неактивен

 

#17 17.06.2010 18:13:49

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

Я последние часы именно вникал в идею, копипастил в строку ввода запроса ,чтобы сперва проверить, что это работает, а затем изучал, что мы делаем.

Ошибки были выданы, используя mysql в комплекте денвер.

Из результата видно, что получили по 2 значения для А и B. А как же быть тогда, если есть строки с именами C,D,E... и их значениями, и требуется, чтобы их 10 выводило?
В mssql для этого вроде есть функция top, а тут только лимитами пользоваться или без них можно будет получить нужный результат?

Отредактированно uNsLide (17.06.2010 18:15:48)

Неактивен

 

#18 17.06.2010 18:34:49

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Запрос на вывод 10 лучших результатов

Ну, если бы у меня были данные про C, то и С бы появилось — для того, чтобы
проверить работоспособность запроса мне хватило двух букв.

Про 10 букв Вы ничего не говорили изначально. Как простой хак — можете добавить
в WHERE условие name BETWEEN 'a' AND 'j'.

Неактивен

 

#19 17.06.2010 18:48:49

uNsLide
Участник
Зарегистрирован: 17.06.2010
Сообщений: 13

Re: Запрос на вывод 10 лучших результатов

В самом первом моем сообщении данные про C были...
И 10 букв здесь не причем. 10 лучших записей по ранку по убыванию.

А вот и ошибка, из-за которой выдавались ошибки.

WHERE (
test.name = s.name
AND NOT test.rank = s.rank

А первоначально я писал в запрос используя ваш первоначальный запрос: Where Not(...)...

Добавил в свою таблицу дополнительные имена D,E..
Получается, что условие в Where name between не нужно, запрос самодостаточен и выдает, что требуется.
Окончательный вид запроса у меня получился такой
(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
LIMIT 10;

и выводит:
name    rank
A    87
A    70
B    90
B    85
C    89
C    56
D    93
D    64
E    64
Огромное спасибо за оказанную помощь. Очень благодарен вам.

Отредактированно uNsLide (17.06.2010 18:50:55)

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson