简体   繁体   中英

PostgreSQL, finding and fixing overlapping time periods

I have time periods spent in different units per user in a table. The time periods overlap and I would like to fix that. I have:

user|unit|start_time|end_time
   1|   1|2015-01-01|2015-01-31
   1|   2|2015-01-07|2015-01-14
   2|   1|2015-01-09|2015-01-13
   2|   2|2015-01-10|2015-01-15

ie. user 1 started at unit 1 on 2015-01-01, transfered to unit 2 on 2015-01-07, returned to unit 1 on 2015-01-14 and left unit 1 on the 2015-01-31. The user can't be in two places at once so the table should look more like this:

user|unit|start_time|end_time
   1|   1|2015-01-01|2015-01-07 --fixed end_time
   1|   2|2015-01-07|2015-01-14
   1|   1|2015-01-14|2015-01-31 --newly created line
   2|   1|2015-01-09|2015-01-10 --fixed end_time
   2|   2|2015-01-10|2015-01-15

Here is some SQL to create the test table with some entries.

CREATE TABLE users_n_units
(
users character varying (100),
units character varying (100),
start_time date,
end_time date
);

INSERT INTO users_n_units (users,units,start_time,end_time) 
VALUES ('1','1','2015-01-01','2015-01-31'),
       ('1','2','2015-01-07','2015-01-14'),
       ('2','1','2015-01-09','2015-01-13'),
       ('2','2','2015-01-10','2015-01-15');

You don't really give enough information to fully answer this, and as others have pointed out you may end up with special cases so you should analyze what your data looks like carefully before running updates.

But in your test environment you can try something like this. The trick is to join your table to itself with clauses that restricts you to the data that matches your business logic properly, and then update it.

This statement works on your tiny sample set and just runs through and mechanically sets end times to the following time period's start times. I have used something very similar to this on similar problems before so I know the mechanism should work for you.

CAUTION: not tested on anything other than this small set. Don't run on production data!

UPDATE a SET a.end_time = b.start_time 
FROM users_n_units a 
INNER JOIN users_n_units b ON a.users = b.users AND a.units < b.units

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM