左连接到两个内连接表

时间:2012-12-13 14:09:04

标签: sql sql-server

我确信我可能只是在忘记或过于复杂......但这是我的情景:

日历表(每年的每一天的记录)

iso_date
01/01/01
02/01/01
03/01/01
04/01/01

场地表(每个场地的记录)

venue
All London
London Tower
London Bridge
Millenium Bridge

复合场地表(参考相关场地)

master_venue,     child_venue
All London,       All London
All London,       London Tower
All London,       London Bridge
All London,       Millenium Bridge
London Tower,     London Tower
London Bridge,    London Bridge
Millenium Bridge, Millenium Bridge

预订表(每次预订的记录,包括日期和地点)

iso_date, venue,            event
01/01/01, All London,       1
02/01/01, London Tower,     2
02/01/01, Millenium Bridge, 3
04/01/01, London Bridge,    4

事件表

event, status
1,     1
2,     0
3,     1
4,     1

现在我想加入这些表格,这样我每天都可以获得每个场地的记录,无论是否已经预订。如果场地有预订,我只想在事件状态为1时看到它。

输出

iso_date, venue,            booked
01/01/01, All London,       1
01/01/01, London Tower,     1
01/01/01, London Bridge,    1
01/01/01, Millenium Bridge, 1
02/01/01, All London,       0
02/01/01, London Tower,     0
02/01/01, London Bridge,    0
02/01/01, Millenium Bridge, 1
03/01/01, All London,       0
03/01/01, London Tower,     0
03/01/01, London Bridge,    0
03/01/01, Millenium Bridge, 0
04/01/01, All London,       0
04/01/01, London Tower,     0
04/01/01, London Bridge,    1
04/01/01, Millenium Bridge, 0

我无法在where子句中使用事件状态,因为它将完全删除记录。

我知道我可以使用子查询或一些复杂的case语句,但是我可以智能地加入表来解决我的问题吗?

3 个答案:

答案 0 :(得分:6)

你应该写:

SELECT Calendar.iso_date AS iso_date,
       Venues.venue AS venue,
       COALESCE(Events.status, 0) AS booked
  FROM Calendar
 CROSS
  JOIN Venues
  LEFT
 OUTER
  JOIN (      Bookings
         JOIN Events
           ON Events.event = Bookings.event
          AND Events.status = 1
       )
    ON Bookings.iso_date = Calendar.iso_date
   AND Bookings.venue = Venues.venue
;

(免责声明:未经测试。)

答案 1 :(得分:0)

您需要从驾驶表开始,这是日历和场地的交叉连接。然后,加入预订以获取预订信息:

select c.iso_date, v.venue,
       (case when b.event is NULL then 0 else 1 end) as Booked
from calendar c cross join
     venues v left outer join
     bookings b
     on b.iso_date = c.iso_date and
        b.venue = v.venue

答案 2 :(得分:0)

select iso_date, 
       venue,
       max(case when events.event is not null then 1 else 0 end) as booked
    from calendar
    cross join venue
    left outer join bookings on
        bookings.date  = iso_date and
        bookings.venue = venue.venue
    left outer join events on 
        events.status = 1 and 
        events.event = bookings.event
    group by iso_date, venue

更新:用两个外连接重写了查询,这样即使只获得一小部分记录也会有效。

以下是您如何最有效地获得单一日期和地点的方式:

select iso_date, 
       venue,
       max(case when events.event is not null then 1 else 0 end) as booked
    from calendar
    inner join venue on
        calendar.iso_date = '01/01/01' and
        venue.venue = 'my front lawn'
    left outer join bookings on
        bookings.date  = iso_date and
        bookings.venue = venue.venue
    left outer join events on 
        events.status = 1 and 
        events.event = bookings.event
    group by iso_date, venue