合并多行中的值并删除。 Postgres SQL

时间:2018-09-19 14:24:42

标签: sql postgresql timestamp upsert

我有一个用户可用性表。每行都有一个start timeend time作为时间戳。

当我插入新行时,我检查该行是否与该用户的另一个可用性行重叠,如果确实存在,则更新现有行,如果没有,则添加新行。

问题是当新的可用性与两个现有行重叠时。

例如

'2018-09-01 10:00:00' - '2018-09-01 13:00:00',
'2018-09-01 14:00:00' - '2018-09-01 16:00:00'

并且用户想要添加:

'2018-09-01 11:00:00' - '2018-09-01 17:00:00'.

在这种情况下,第一行将被更新,但第二行将保留在那里。

如何删除/合并所有重叠的行?

我正在使用PostgreSQL

我的SQL

do $$
      begin

        /* Overlapps availabilty */
        IF EXISTS (
          SELECT *
          FROM availabilities
          WHERE ('${startTime}', '${endTime}') OVERLAPS (availabilities.startTime, availabilities.endTime)
          AND availabilities.therapist = ${therapist}
        ) THEN
          UPDATE availabilities
          SET startTime = LEAST(availabilities.startTime, '${startTime}'::timestamp), endTime = GREATEST(availabilities.endTime, '${endTime}'::timestamp)
          WHERE therapist = ${therapist}
          AND ('${startTime}', '${endTime}') OVERLAPS (availabilities.startTime, availabilities.endTime);

        /* New availabilty */
        ELSE
          INSERT INTO availabilities
            (therapist, startTime, endTime)
          VALUES (${therapist}, '${startTime}', '${endTime}');
        END IF;

      end
      $$

更新

我与Michel Milezzi合作,但之前也添加了INSERT。

1 个答案:

答案 0 :(得分:1)

已编辑

为了获得所有重叠行的最短开始时间和最长结束时间,您可以将DELETERETURNINGINSERT混合使用:

WITH overlapping AS (
    DELETE FROM
        availabilities 
    WHERE 
        (starttime, endtime) OVERLAPS ('2018-09-01 11:00:00','2018-09-01 17:00:00') 
        AND therapist = 1
    RETURNING 
        therapist, 
        starttime, 
        endtime    
)
INSERT INTO  
    availabilities (therapist, starttime, endtime) 
SELECT 
    therapist, 
    least(min(starttime), '2018-09-01 11:00:00'), 
    greatest(max(endtime),'2018-09-01 17:00:00') 
FROM
    overlapping
GROUP BY
    therapist;

上一个答案:

我不确定我是否理解正确,但是看来您已经很接近答案了:

--sample
CREATE TABLE availabilities (therapist, starttime, endtime) AS 
    VALUES 
        (1, '2018-09-01 10:00:00'::TIMESTAMP, '2018-09-01 13:00:00'::TIMESTAMP),
        (1, '2018-09-01 14:00:00', '2018-09-01 16:00:00'),
        (1, '2018-10-01 14:00:00', '2018-10-01 16:00:00'),
        (2, '2018-09-01 14:00:00', '2018-09-01 16:00:00');

--remove overlapping availabilities    
DELETE FROM 
    availabilities 
WHERE 
    (starttime, endtime) OVERLAPS ('2018-09-01 11:00:00','2018-09-01 17:00:00') 
    AND therapist = 1;

--insert new availability
INSERT INTO 
    availabilities (therapist, starttime, endtime) 
VALUES 
    (1, '2018-09-01 11:00:00','2018-09-01 17:00:00');

您还可以在插入操作之前添加排除约束以对其进行验证:

--In order to use scalar values (e.g.: therapist) on gist indexes we need this extension
CREATE EXTENSION btree_gist;
--Now we can add our new constraint
--Be careful with timezone issues, tsrange will discard timezone data
ALTER TABLE availabilities 
    ADD EXCLUDE USING gist(therapist WITH =, tsrange(starttime, endtime) WITH &&);

有关范围运算符here的更多信息。