Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Составление SQL-запросов > Вывести для каждой команды самого молодого игрока


Автор: 4epT 11.11.2011, 00:06
Имеется 2 таблицы: team и player.

Team:
id (ключ)
team (название)

Player:
id (ключ)
name (имя)
id_team (номер команды в которой он играет)
birthdate (день рождения)

Запрос должен содержать в себе Имя команды, Имя игрока и дату рождения. Дата рождения должна быть самая маленькая (самый старый) или самая большая (самый молодой).

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

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





p.s. и был бы признателен, если бы кто то смог дать список задач по sql, штук 100 - 150 задач отсортированные по уровню сложности =) начиная с обычных select и заканчивая очень сложными =) Ну или какие нибудь источники по которым моно было бы очень хорошо подготовиться!



Автор: Akina 11.11.2011, 07:57
Цитата(4epT @  11.11.2011,  01:06 Найти цитируемый пост)
при попытке вывести еще имя игрока ругается ( говорит что по нему нужно делать группировку, а судя по логике запроса группировка должна быть только по команде.

Используйте не просто вывод имени, а агрегатную функцию от него  (First, например - есть его в Вашей СУБД?)...

Автор: Zloxa 11.11.2011, 10:12
Цитата(4epT @  11.11.2011,  00:06 Найти цитируемый пост)
Запрос должен содержать в себе Имя команды, Имя игрока и дату рождения. Дата рождения должна быть самая маленькая (самый старый) или самая большая (самый молодой).


Код

select team
       ,name
       ,birthdate
from 
  (select team.team
    ,player.name
    ,player.birthdate
    ,row_number() -- или dense_rank, если должны быть выведены все игроки у которых дата рождения одинакова и минимальна
      over (partition by player.id_team 
            order by player.birthdate --desc -- для самого старого
           ) rnk
   from player,team
   where player.id_team = team.id
  )
where rnk = 1


+ поиск по форуму по "бабушкин метод", хотя тут он не нужен
Цитата(4epT @  11.11.2011,  00:06 Найти цитируемый пост)
если бы кто то смог дать список задач по sql, штук 100 - 150 задач отсортированные по уровню сложности =) 


sql-ex.ru

Автор: 4epT 11.11.2011, 11:44
В том то и дело что не понятно какую агрегатную функцию можно там применить ... для дня рождения используется min или max. 

Насчет first сейчас посмотрю ... 

Автор: 4epT 11.11.2011, 12:14
В том то и дело что не понятно какую агрегатную функцию можно там применить ... для дня рождения используется min или max. 

Насчет first сейчас посмотрю ... 

Автор: 4epT 11.11.2011, 13:59
Zloxa, именно такой способ мой друг мне и подсказал =) Скажи пожалуйста, этот запрос самый "красивый" ? по другому не сделаешь ?

За сайт спасибо, посмотрю =)

Автор: Zloxa 11.11.2011, 15:34
Цитата(4epT @  11.11.2011,  13:59 Найти цитируемый пост)
 этот запрос самый "красивый" ?

Мне - нравится. 
row_number вроде как описан в SQL2003 и из года в год больше и больше платформ его потдерживают.

Цитата(4epT @  11.11.2011,  13:59 Найти цитируемый пост)
по другому не сделаешь ?

Акина подсказал first, гугл подсказал что в ПГ есть что-то подобное, но, похоже это не встроенный аггрегат, а определяемый пользователем. По кр. мере в списке http://www.postgresql.org/docs/9.1/interactive/functions-aggregate.html я его не углядел. Если это так, испльзовать его можно не всегда и не везде.

В оракле есть конструкция keep 
Ее тоже можно использовать для этих целей
Код

select max(team.team) team
       ,max(player.name) keep (dense rank last order by player.birthdate) name
       ,max(player.birthdate) birthdate
  from player,team
  where player.id_team = team.id
  group by player.team_id

но я не знаю, есть ли подобная плюшка в ПГ и держит ли ее вобще ктонить кроме оракла.

Можно испльзовать скалярный подзапрос
Код

select team.team
       ,(select max(name) 
           from player 
           where player.id_team = s.id_team 
           and player.birthdate = s.max_birthdate
         ) name
        ,s.max_birthdate birthdate
from (
  select player.id_team
       ,max(player.birthdate) max_birthdate
  from player
  group by player.team_id
) s
inner join team on s.id_team = team.id

Такой запрос будет рабоатть на подавляющем большинстве платформ, т.к. опирается на синтаксис стандарта sql98

Можно сделать через join
Код

select
  team.team
  ,player.name
  ,s.max_birthdate birthdate
from ( 
  select player.id_team
      ,max(player.birthdate) max_birthdate
  from player
  group by player.team_id
 ) s
inner join team on s.id_team = team.id
inner join player on player.id_team = s.id_team 
                     and player.birthdate = s.max_birthdate

Этот запрос, тоже опирается на синтаксис sql98, но, в отличии от предыдущих, выведет всех игроков дата рождения которых максимальна. К сожалению, как разрешать такие неоднозначности, в исходной постановке вопроса не указано, а всякий раз спрашивать, уже оскомину набило.

наверное еще как-то можно.

Автор: Zloxa 11.11.2011, 16:27
Цитата(Zloxa @  11.11.2011,  15:34 Найти цитируемый пост)
еще как-то

Код

select team.team
    ,p1.name
    ,p1.birthdate
   from player p1,team
   where p1.id_team = team.id
      and not exists (select null 
                      from player p2 
                      where p1.player= p2.player
                            and p1.birthdate > p2.birthdate
                      )

Тоже 98й синтаксис но работать будет чутку по другому нежели предыдущие два запроса, в части нуллов

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)