如何根据星期几返回包含日历日期的记录?

时间:2017-03-29 14:20:55

标签: sql postgresql

我有以下架构:

计划表示重复活动的时间表。

# Table name: schedules
#
#  id         :integer          not null, primary key
#  start_date :date
#  end_date   :date

天数表示活动发生的时间表的WEEKday。

# Table name: days
#
#  id          :integer          not null, primary key
#  schedule_id :integer
#  wday        :integer

TimeSlots表示活动可能发生的小时数(可能每天很多)。

# Table name: time_slots
#
#  id           :integer          not null, primary key
#  day_id       :integer
#  start_time   :time             not null
#  end_time     :time             not null

示例数据集可以是:

  • 1开始日期为6月1日,截止日期为6月30日
  • 1天,宽度wday = 0(6月每周一活动)
  • 2 TimeSlots。 1与start_hour上午8点和end_hour上午11点。另一个是start_hour下午1点和end_hour下午3点

鉴于上面的例子(在下面的SQL中表示),我想在六月份的每个星期一返回一条记录,包括它们的日历日期。

2017年6月有4个星期一,所以上面的例子看起来像:

 id | wday | calendar_date |
----+------+---------------+
  1 |    2 |    2017-06-05 |
  1 |    2 |    2017-06-12 |
  1 |    2 |    2017-06-19 |
  1 |    2 |    2017-06-26 |

有人能引导我朝着正确的方向前进吗?

在下面设置PSQL:

CREATE TABLE schedules (
    id integer NOT NULL,
    start_date date,
    end_date date);

CREATE TABLE days (
    id integer NOT NULL,
    schedule_id integer,
    wday integer);

CREATE TABLE time_slots (
    id integer NOT NULL,
    start_time time,
    end_time time,
    day_id integer);

INSERT INTO schedules (id, start_date, end_date) VALUES (1, '2017-06-01', '2017-06-30');
INSERT INTO days (id, schedule_id, wday) VALUES (1, 1, 0);
INSERT INTO time_slots (id, start_time, end_time, day_id) VALUES (1, '18:00', '19:00', 1);

1 个答案:

答案 0 :(得分:2)

select     s.id, wday, start_date + g calendar_date
from       schedules s
cross join generate_series(0, end_date - start_date) g
join       days d on d.schedule_id = s.id
where      extract(isodow from start_date + g) - 1 = wday

http://rextester.com/GTPQ53700

注意:

  • 使用generate_series()您可以生成行,而数据库中没有数据
  • 我假设您希望周一开始几周(因为它在您的表中由0表示)。与PostgreSQL最接近的是ISODOW,但周一至周日使用1-7。 (DOW,另一方面,周日至周一使用0-6:所以周日从周日开始DOW。)
  • 这实际上并没有考虑time_slots。如果需要,请将以下谓词添加到WHERE子句中:

    and exists(select 1 from time_slots t where t.day_id = d.id)