0

我有一个包含预约时间段的表,我尝试用 sql 语句/视图找出一种方法来查找不同持续时间的预约的相邻空闲时间段。

创建表如下所示:

CREATE TABLE timeslot
(
  timeslot_id bigserial NOT NULL,
  duration bigint,
  successor bigint,
  predecessor bigint,
  start_year character varying NOT NULL,
  start_month character varying NOT NULL,
  start_day character varying NOT NULL,
  start_hour character varying NOT NULL,
  start_minute character varying NOT NULL,
  end_year character varying NOT NULL,
  end_month character varying NOT NULL,
  end_day character varying NOT NULL,
  end_hour character varying NOT NULL,
  end_minute character varying NOT NULL,
  employee_id integer NOT NULL,
  available_status_id integer,
  appoint_calendar_id integer
  CONSTRAINT timeslot_id PRIMARY KEY (timeslot_id),
  CONSTRAINT appoint_calendar_id FOREIGN KEY (appoint_calendar_id)
  REFERENCES appoint_calendar (appoint_calendar_id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT available_status_id FOREIGN KEY (available_status_id)
  REFERENCES available_status (available_status_id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT employee_id FOREIGN KEY (employee_id)
  REFERENCES employee (employee_id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION
)

以下是插入数据示例,其中 available_status_id 为 1 表示空闲时隙,available_status_id 为 2 表示空闲时隙:

INSERT INTO timeslot(
        timeslot_id, duration, successor, predecessor, start_year, start_month, 
        start_day, start_hour, start_minute, end_year, end_month, end_day, 
        end_hour, end_minute, employee_id, available_status_id, appoint_calendar_id)
VALUES (11870, 30, null, 11869, "2013", "09", 
        "02", "18", "00", "2013", "09", "02", 
        "18", "30", 4, 1, null);

INSERT INTO timeslot(
        timeslot_id, duration, successor, predecessor, start_year, start_month, 
        start_day, start_hour, start_minute, end_year, end_month, end_day, 
        end_hour, end_minute, employee_id, available_status_id, appoint_calendar_id)
VALUES (11904, 30, 12000, 11999, "2013", "09", 
        "09", "10", "30", "2013", "09", "09", 
        "11", "00", 5, 2, 761);

我正在 postgres 中查找查询,以查找 15、30 或 60 分钟等不同持续时间的约会的所有免费时间段。目前,我只是从数据库中获取所有空闲时隙并在 Java 中对其进行迭代并将持续时间的分钟数相加,直到找到足够的相邻时隙,然后返回每个子组的第一个时隙以显示在日历中。但是在 postgres 中一定有更好更快的方法吗?提前致谢

编辑

输入是以分钟为单位的所需持续时间(例如 60)、employee_id(例如 5)和日期(例如 09.09.2013)。所需输出是所有相邻(在时间上)、空闲且有足够持续时间的子集。对于上面的示例,这可能是:

时隙_id 11904
持续时间 30
继任者 12000
前身 11999
2013 年开始
开始月 09
开始日 09
开始小时 10
开始分钟 30
2013 年底
end_month 09
end_day 09
end_hour 11
end_minute 00
员工 ID 5
available_status_id 1
任命日历 ID 空

时隙 ID 12000
持续时间 30
继任者 11906
前身 11904
2013 年开始
开始月 09
开始日 09
开始小时 11
开始分钟 00
2013 年底
end_month 09
end_day 09
end_hour 11
end_minute 30
员工 ID 5
available_status_id 1
任命日历 ID 空
4

2 回答 2

1

就个人而言,我认为在 Java 代码中进行此操作是个好主意。

其他选项可能是使用游标创建 PostgreSQL 函数。

但是,如果您真的想在一个 SQL 请求中执行此操作,并且假设您的 timeslot_id 与每个连续的时间段正好相差一个,并且您可以预测最大约会持续时间和所需的时间段数,您可以尝试以下操作:

select ts1.timeslot_id as start_timeslot_id, 
    coalesce(t4.timeslot_id, t3.timeslot_id, t2.timeslot_id, t1.timeslot_id) as end_timeslot_id, 
    coalesce(t4.end_hour, t3.end_hour, t2.end_hour, t1.end_hour)*60+coalesce(t4.end_minute, t3.end_minute, t2.end_minute, t1.end_minute) - t1.start_hour*60+t1.start_minute as duration_minutes
from timeslot ts1
left join timeslot ts2 
on ts1.timeslot_id+1 = ts2.timeslot_id
and t12.available_status_id = 1 
left join timeslot ts3 
on ts2.timeslot_id+1 = ts3.timeslot_id
and ts3.available_status_id = 1 
left join timeslot ts4 
on ts3.timeslot_id+1 = ts4.timeslot_id
and ts4.available_status_id = 1 
where ts1.start_year = '2013' -- these all are your input parameters
and ts1.start_month = '09'
and ts1.start_day = '09'
and employee_id = 5
and coalesce(t4.end_hour, t3.end_hour, t2.end_hour, t1.end_hour)*60+coalesce(t4.end_minute, t3.end_minute, t2.end_minute, t1.end_minute) - t1.start_hour*60+t1.start_minute >= 60 -- duration in minutes

据推测,此请求将为您提供大于或等于所需时间段的所有可能时间段。我没有尝试对真实数据库运行此查询,因此它可能包含错误。

于 2013-09-05T08:57:01.690 回答
0
CREATE TABLE appoint_calendar ( appoint_calendar_id SERIAL NOT NULL PRIMARY KEY);
INSERT INTO appoint_calendar(appoint_calendar_id) VALUES (761),(762);

CREATE TABLE employee (employee_id SERIAL NOT NULL PRIMARY KEY);
INSERT INTO employee(employee_id) VALUES (4),(5);

CREATE TABLE available_status (available_status_id SERIAL NOT NULL PRIMARY KEY);
INSERT INTO available_status(available_status_id) VALUES (1),(2);


CREATE TABLE timeslot
( timeslot_id bigserial NOT NULL PRIMARY KEY
  , duration bigint
  , successor bigint
  , predecessor bigint
  , start_date timestamp with time zone
  , end_date timestamp with time zone
  , employee_id integer NOT NULL
        REFERENCES employee (employee_id) MATCH SIMPLE
        ON UPDATE NO ACTION ON DELETE NO ACTION
  , available_status_id integer
        REFERENCES available_status (available_status_id) MATCH SIMPLE
        ON UPDATE NO ACTION ON DELETE NO ACTION
  , appoint_calendar_id integer
        REFERENCES appoint_calendar (appoint_calendar_id) MATCH SIMPLE
        ON UPDATE NO ACTION ON DELETE NO ACTION
);

INSERT INTO timeslot(timeslot_id, duration,successor,predecessor,start_date,end_date,employee_id,available_status_id,appoint_calendar_id) VALUES
    (11870, 30, null, 11869, '2013-09-02 18:00:00', '2013-09-02 18:30:00', 4, 1, null)
  , (11904, 30, 12000, 11999, '2013-09-09 10:30:00', '2013-09-09 11:00:00', 5, 2, 761)
        ;

选择一些时隙(区间算术不完全正确,YMMV)

SELECT * FROM timeslot ts
WHERE ts.employee_id IN(5)
AND ts.available_status_id IN(1, 2)
AND ts.start_date::date = '2013-09-09'::date
AND ts.end_date >= (ts.start_date + '30 min'::interval)
        ;
于 2013-09-05T09:19:00.303 回答