Как выбрать Макс в этом запросе?Помощь на экзамене - PullRequest
0 голосов
/ 26 февраля 2012

Итак, я собираюсь выполнить множество упражнений для финального экзамена по SQL, который у меня есть в четверг, и я натолкнулся на другой вопрос, по поводу которого у меня есть сомнения.быть из отеля DB.У вас есть три таблицы:

    STAY               ROOM                  ROOM_TYPE
    ===========        ============          ============
PK  ID_STAY        PK  ID_ROOM           PK  ID_ROOM_TYPE
    DAYS_QUANT         ID_ROOM_TYPE  FK      DESCRIPTION
    DATE               PRICE
    ID_ROOM  FK

Запрос, который они просят меня сделать, это "Показать все данные для комнаты, которая была арендована на наибольшее количество дней (всего) в 2011 годуПо типу комнаты (необходимо указать ID Тип и описание комнаты) "

Я решил это так, я не знаю, нормально ли это:

  SELECT RT.ID_ROOM_TYPE, RT.DESCRIPTON, R.*, SUM(S.DAYS_QUANT)
    FROM STAY S, ROOM R, ROOM_TYPE RT
   WHERE YEAR(S.DATE) = '2011'
GROUP BY RT.ID_ROOM_TYPE, RT.DESCRIPTON, R.*
ORDER BY SUM(S.DAYS_QUANT) DESC
   LIMIT 1

Итак, первое, в чем я не уверен, это Р. * Я включил.Могу ли я поместить это в SELECT?Можно ли его так же включить в GROUP BY?

Еще одна вещь, в которой я не уверен, будет ли мне разрешено использовать операторы LIMIT или SELECT TOP 1 на экзамене.Кто-нибудь может придумать способ решить эту проблему, не используя их?как с оператором MAX () или что-то?

Ответы [ 5 ]

1 голос
/ 27 февраля 2012

Я считаю, что вы не можете использовать CTE, поэтому я расширил последнюю часть ответа Стива Касс.Вы можете получить желаемые результаты без предложений TOP или Limit, сравнивая общее количество дней, в течение которых комната была занята, с максимальным общим количеством дней, в течение которых была занята любая комната того же типа.Для этого сначала нужно сложить дни по комнатам, а затем, используя идентичные производные таблицы, получить максимум дней по типу комнаты.Соединяя их по типу комнаты и дням, вы изолируете большинство используемых комнат.Затем вы присоединяетесь к стартовым таблицам, чтобы показать все данные.В отличие от TOP или Limit, это приведет к большему количеству записей в случае ничьей.

PS Это НЕ проверено.Я верю, что это сработает, но это может быть опечатка.

select r.*, rt.*, roomDays.TotalDays
from Room r inner join Room_type rt
   on r.id_room_type = rt.id_room_type
   inner join 
      (select id_room, id_room_type, sum(days_quant) TotalDays
      from Stay
         inner join Room
           on Stay.id_room = Room.id_room
      where year(Date) = 2011
      group by id_room, id_room_type) roomDays
   on r.id_room = roomDays.id_room
   inner join 
      (select id_room_type, max(TotalDays) TotalDays
      from 
         (select id_room, id_room_type, sum(days_quant) TotalDays
          from Stay
             inner join Room
               on Stay.id_room = Room.id_room
          where year(Date) = 2011
          group by id_room, id_room_type) roomDaysHelper
      group by id_room_type) roomTypeDays
   on r.id_room_type = roomTypeDays.id_room_type
   and roomDays.TotalDays = roomTypeDays.TotalDays
1 голос
/ 26 февраля 2012

Всегда можно избежать LIMIT 1 или SELECT TOP.Одним из способов является выражение верхней строки как строки, для которой нет верхней строки.WHERE NOT EXISTS выражает идею «для которой нет».

Один из способов думать об этом заключается в следующем: выберите те комнаты (вместе с их общим количеством дней и типовой информацией), для которых нет места.того же типа с большим количеством общих дней.Это дает вам этот запрос (не тщательно вычитанный):

with StayTotals as (
  select
    STAY.ID_ROOM, 
    ROOM_TYPE.ID_ROOM_TYPE,
    ROOM_TYPE.DESCRIPTION,
    SUM(STAY.DAYS_QUANT) AS TotalDays2011
  from STAY join ROOM on STAY.ID_ROOM = ROOM.ID_ROOM
            join ROOM_TYPE on ROOM.ID_ROOM_TYPE = ROOM_TYPE.ID_ROOM_TYPE
  where YEAR(STAY.DATE) = 2011
  group by STAY.ID_ROOM, ROOM_TYPE.ID_ROOM_TYPE, ROOM_TYPE.DESCRIPTION
)
  select *
  from StayTotals as T1
  where not exists (
    select *
    from StayTotals as T2
    where T2.ID_ROOM_TYPE = T1.ID_ROOM_TYPE
    and T2.TotalDays2011 > T1.TotalDays2011
  );

Если вы не можете использовать CTE (предложение WITH), вы можете переписать его, используя подзапросы, но это неудобно.

Функции ранжирования уже давно являются частью стандарта SQL.Если вы можете использовать их, это также может работать:

with StayTotals as (
  select
    STAY.ID_ROOM, 
    ROOM_TYPE.ID_ROOM_TYPE,
    ROOM_TYPE.DESCRIPTION,
    SUM(STAY.DAYS_QUANT) AS TotalDays2011
  from STAY join ROOM on STAY.ID_ROOM = ROOM.ID_ROOM
            join ROOM_TYPE on ROOM.ID_ROOM_TYPE = ROOM_TYPE.ID_ROOM_TYPE
  where YEAR(STAY.DATE) = 2011
  group by STAY.ID_ROOM, ROOM_TYPE.ID_ROOM_TYPE, ROOM_TYPE.DESCRIPTION
), StayTotalsRankedByType as (
  select
    ID_ROOM, 
    ID_ROOM_TYPE,
    DESCRIPTION,
    TotalDays2011,
    RANK() OVER (
      PARTITION BY ID_ROOM_TYPE
      ORDER BY TotalDays2011 DESC
    ) as RankInRoomType
  from StayTotals
)
  select
    ID_ROOM, 
    ID_ROOM_TYPE,
    DESCRIPTION,
    TotalDays2011
  from StayTotalsRankedByType
  where RankInRoomType = 1;

Наконец, еще один способ добавить дополнительные столбцы для описания сгруппированных результатов MAX - это использовать сортировку «carryalong», которая была удобной техникой.до ранжирования функции были доступны.Адам Маханич приводит пример здесь , и на эту тему из Usenet есть полезные темы, такие как this .

1 голос
/ 26 февраля 2012
select r.*, t.*
  from room r
  join room_type t on t.id_room_type = r.id_room_type
 where r.id in
       (select
               (select r.id_room
                  from room r
                  join stay on stay.id_room = r.id_room
                 where year(s.date) = '2011'
                   and r.id_room_type = t.id_room_type
                 group by r.id_room
                 order by sum(s.days_quant) desc
                 limit 1) room_id
          from room_type t)
0 голосов
/ 27 февраля 2012

Спасибо всем!со всеми идеями, которые вы мне дали, я придумал это, дайте мне знать, если вы считаете, что это нормально, пожалуйста!

SELECT R.ID_ROOM, R.ID_ROOM_TYPE, T.DESCRIPTION, SUM(S.DAYS_CUANT)
FROM ROOM R, ROOM_TYPE T, STAY S
(SELECT ID_STAY, SUM(S.DAYS_QUANT) TOTALDAYS
 FROM STAY S
 WHERE YEAR(S.DATE) = 2011
 GROUP BY S.ID_STAY) STAYHELPER
WHERE YEAR(S.DATE) = 2011 
GROUP BY R.ID_ROOM, R.ID_ROOM_TYPE, T.DESCRIPTION
HAVING SUM(S.DAYS_QUANT) >= ALL STAYHELPER.TOTALDAYS
0 голосов
/ 26 февраля 2012

Как насчет этого?

select room.id_room, room_type.description, room.price
from room inner join room_type 
on room.id_room.type = room_type.id_room_type
where room.room_id = (select room_id from stay
where year (date) = 2011
group by id_room
order by sum (days_quant) desc);

К сожалению, этот запрос (как и сейчас) не показывает, как в течение многих дней была арендована самая популярная комната. Но нет «лимита 1»!

...