LEFT JOIN包含数据

时间:2017-09-27 19:31:50

标签: sql postgresql

我有一个处理学校假期的申请。不幸的是,有三种不同的学校假期:全国范围,联邦州和城市假期。我将所有信息存储在表days,表vacation_periods和连接表slots中:

days {
    id:integer
    date_value:date
}
slots {
    id:integer
    day_id:integer
    vacation_period_id:integer
}
vacation_periods {
    id:integer
    starts_on:date
    ends_on:date
    name:string
    country_id:integer
    federal_state_id:integer
    city_id:integer
}

我想在特定时间范围内选择所有days。让我们说2017年1月1日到2017年1月31日。我可以通过以下方式获取days

SELECT * FROM days WHERE date_value >= '2017-01-01' AND 
                         date_value <= '2017-01-31';

但对于我的假期日历,我不仅需要days,还需要vacation_periods所在的信息。假设我搜索那个时间范围内有

的所有vacation_periods
country_id == 1 or federal_state_id == 5 or city_id == 30

我读过有关JOINS和LEFT JOINS的内容,这似乎是问题的解决方案。但我不能把所有东西都放在一起。

是否可以发送一个SQL请求,该请求在请求的时间范围内返回所有days,如果符合vacation_period规则的country_id == 1 or federal_state_id == 5 or city_id == 30通过{{1}连接,则可以发送其他信息每个slots。包括day的名称?

如果一个请求不可能:哪个是在数据库中解决此问题的最快方法?请求多少?什么样的要求?

如果可能的话,我希望得到某种形式的结果:

vacation_period

3 个答案:

答案 0 :(得分:1)

以下查询可能会为您提供所需的答案:

SELECT * FROM days WHERE date_value >= '2017-01-01' AND date_value <='2017-01-31'

INNER JOIN slots ON days.id = slots.day_id

INNER JOIN vacation_periods ON vacation_periods.id = slots.vacation_period_id

答案 1 :(得分:0)

我认为您可以使用

获得所需内容的未格式化版本(可以将其处理为分层输出)
CREATE TYPE vacation_authority AS ENUM
  ('COUNTY', 'FED-STATE', 'CITY');
/* not necessary, but cleans up the vacation_period table */

更改为允许vacation_period只有一个ID,以及authority类型的新字段vacation_authority。您现在可以使用id字段或(id,权限)创建主键,具体取决于休假数据进入系统的方式。

SELECT date_value, vp.name, vp.id /* is the ID meaningful or arbitrary? */
FROM dates LEFT JOIN vacation_periods vp
WHERE date_value BETWEEN vp.starts_on AND vp.ends_on; -- inclusive range

现在,如果跨越给定日期有多个假期,那么这将是输出中的多个记录。在这种情况下,你不清楚你想要什么。

答案 2 :(得分:0)

其他答案都没有能够解决我的问题,但他们让我解决了这个问题,所以我很感激他们。这是解决方案:

SELECT days.date_value, slots.period_id, vacation_periods.name FROM days 
LEFT OUTER JOIN slots ON (days.id = slots.day_id) 
LEFT OUTER JOIN vacation_periods ON (slots.period_id = vacation_periods.id) 
WHERE days.date_value >= '2017-01-05' 
AND days.date_value <='2017-01-15' 
AND (vacation_periods.id IS NULL 
OR vacation_periods.country_id = 1 
OR vacation_periods.federal_state_id = 5) 
ORDER BY days.date_value;

Screenshot of the SQL Query output.