2012-02-26 4 views
0

그래서 나는 목요일에 마지막으로 끝난 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 년 (총에) 일의 높은 금액으로 임대 된 객실에 대한 은 "모든 데이터입니다

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 

그래서, 제일 먼저 아니에요 "

이 내가 그것을 해결하는 방식이 나는 괜찮은지 어떤지 모른다이다 (당신은 ID의 객실 타입 및 설명을 보여 주셔야합니다) 물론, 그 R. * 내가 포함되어 있습니다. 내가 SELECT에 넣을 수 있을까요? 그것도 GROUP BY에 포함될 수 있습니까?

시험에서 LIMIT 또는 SELECT TOP 1 문을 사용할 수 있는지 확실하지 않은 다른 사항. 누구든지 이것을 사용하지 않고 이것을 해결할 수있는 방법을 생각할 수 있습니까? MAX() 문 또는 무엇인가?

+1

'LIMIT'는 ANSI가 아니며 MySQL, PostgreSQL 및 SQLite에서만 지원됩니다. 'FETCH FIRST # ROWS'는 ANSI입니다 만, 최근에야 ... –

+0

@OMG Ponies 그래서 교수님은 최근에 ANSI에 최근에 추가되었으므로 교수님이 시험에서 그걸 허락하지 않으실 겁니다. 나는이 쿼리를 수행하는 또 다른 방법을 찾았습니다. – nachoargentina

답변

1

나는 CTE를 사용할 수 없다고 생각하므로 Steve Kass의 대답의 마지막 부분을 확장했습니다. 동일한 유형의 방이 사용 된 최대 총 일수로 객실이 사용 된 총 일수를 비교하여 TOP 또는 제한 조항없이 원하는 결과를 얻을 수 있습니다. 이렇게하려면 먼저 일별 합계를 계산 한 다음 동일한 파생 테이블을 사용하여 일별 최대 일 수를 계산합니다. 두 사람을 방의 유형과 날짜로 합치면 대부분의 방을 격리 할 수 ​​있습니다. 그런 다음 시작 테이블을 조인하여 모든 데이터를 표시합니다. TOP 또는 제한과 달리이 옵션은 동점 일 경우 더 많은 레코드를 생성합니다.

P. 이것은 테스트되지 않았습니다. 나는 그것이 효과가있을 것이라고 믿는다. 그러나 오타가 있을지도 모른다.

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 
+0

이 쿼리 주셔서 감사합니다! 당신은 나에게 FROM 절에 "돕는 테이블"을 만들어서 이것을하는 방법에 대한 좋은 아이디어를 주었다. 답변으로 게시했습니다. 괜찮 으면 내게 알릴 수 있다면 appretiate로 연락하십시오. – nachoargentina

+0

상상력이 풍부하지만 불행히도 효과가 없을 것입니다. ALL은 하위 쿼리를 필요로합니다. 게다가, 파생 된 테이블에서 id_stay 대신 id_room을 사용하는 것이 좋습니다. 그런데 코드에 조인을 넣지 않는 것으로 나타났습니다. 귀하의 SQL 엔진이 일종의 자연 조인을 수행합니까, 아니면 간단하게 생략합니까? –

+0

예, 간결하게하기 위해 생략했습니다. Tx! – nachoargentina

1
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

좋은 방법이지만이 방법도 "제한 1"을 사용합니다. "제한"또는 "최상위 선택"문 없이는이 작업을 수행하는 쉬운 방법이 있다고 생각하십니까? – nachoargentina

0

어때?

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'은 없습니다!

+0

이것이 효과가 있다고 생각하지 않습니다. 하위 쿼리 (from room_id from ...)는 일반적으로 둘 이상의 값을 반환합니다. (room_id라는 열도 없습니다.) –

1

항상 LIMIT 1 또는 SELECT TOP을 피할 수 있습니다. 한 가지 방법은 상단 행을 더 높은 행이없는 행으로 표현하는 것입니다. 존재하지 않는 곳은 "없다"라는 생각을 표현합니다.

생각해 볼 수있는 한 가지 방법은 다음과 같습니다. 총 일수가 더 많은 동일한 유형의 회의실이없는 회의실을 선택합니다 (총 일수 및 유형 정보 포함). 즉,이 쿼리 (주의 깊게 교정되지 않음) 제공 : 당신이 CTE를합니다 (WITH 절)를 사용할 수없는 경우, 당신은 하위 쿼리를 사용하여 다시 작성할 수 있습니다

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

을,하지만 어색합니다.

랭킹 기능은 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"종류를 사용하는 것입니다 기능을 사용할 수있었습니다. Adam Machanic은 here을 예로 들었고 유즈넷의 주제에 유용한 스레드가 있습니다 (예 : this one).

+0

와우 스티브, 이건 정말 좋은 물건입니다! 나는 당신이 이것에 두는 노력을 정말로 호소합니다. 유감스럽게도, 시험에 CTE를 사용할 수 있다고 생각하지 않습니다. CTE를 가르치지 않았고 프로그램의 일부가 아니기 때문입니다. 하지만 하위 쿼리를 사용하여이를 수행하는 방법에 대한 훌륭한 아이디어를 얻었습니다. 나는 그것에서 무언가를 만들고 그것 답장으로 나 자신을 게시하려고 노력할 것이다. 나는 나중에 당신이 그것을 볼 수 있고 당신이 생각하는 것을 말해 줄 수 있다면 정말로 감사 할 것입니다. 다시 남자! – nachoargentina

0

감사합니다. 네가 내게 준 모든 생각들로 내가 이걸 생각해 냈어. 네가 괜찮다고 생각한다면 알려줘!

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 
관련 문제