-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathunion_of_intervals.sql
100 lines (87 loc) · 3.29 KB
/
union_of_intervals.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
\set ECHO none
\pset format unaligned
SET search_path TO provsql_test,provsql;
-- Union of intervals semiring, Belkis Djeffal
-- See https://inria.hal.science/hal-04342025
CREATE TABLE personnel_intervals(
id SERIAL PRIMARY KEY,
name varchar,
position varchar,
city varchar,
valid_time datemultirange
);
INSERT INTO personnel_intervals (name, position, city, valid_time) VALUES
('John', 'Director', 'New York', '{["2021-01-15","2023-03-22"],["2019-07-10","2020-12-05"]}'),
('Paul', 'Janitor', 'New York', '{["2020-05-28","2022-11-15"],["2018-03-20","2019-09-10"]}'),
('Dave', 'Analyst', 'Paris', '{["2019-12-01","2022-08-15"],["2017-06-10","2018-11-30"]}'),
('Ellen', 'Field agent', 'Berlin', '{["2020-10-15","2023-05-28"],["2018-04-05","2019-11-20"]}'),
('Magdalen', 'Double agent', 'Paris', '{["2018-11-22","2021-09-01"],["2016-07-15","2018-02-28"]}'),
('Nancy', 'HR', 'Paris', '{["2017-08-03","2019-10-25"],["2015-02-10","2017-05-15"]}'),
('Susan', 'Analyst', 'Berlin', '{["2019-04-12","2022-02-01"],["2016-10-05","2018-01-15"]}');
/* The union_intervals semiring */
CREATE OR REPLACE FUNCTION union_intervals_plus_state(state datemultirange, value datemultirange)
RETURNS datemultirange AS
$$
SELECT CASE WHEN state IS NULL THEN value ELSE state + value END
$$ LANGUAGE SQL IMMUTABLE;
CREATE OR REPLACE FUNCTION union_intervals_times_state(state datemultirange, value datemultirange)
RETURNS datemultirange AS
$$
SELECT CASE WHEN state IS NULL THEN value ELSE state * value END
$$ LANGUAGE SQL IMMUTABLE;
CREATE OR REPLACE AGGREGATE union_intervals_plus(datemultirange)
(
sfunc = union_intervals_plus_state,
stype = datemultirange,
initcond = '{}'
);
CREATE OR REPLACE AGGREGATE union_intervals_times(datemultirange)
(
sfunc = union_intervals_times_state,
stype = datemultirange,
initcond = '{(,)}'
);
CREATE OR REPLACE FUNCTION union_intervals_monus(state datemultirange, value datemultirange)
RETURNS datemultirange AS
$$
SELECT CASE WHEN state <@ value THEN '{}'::datemultirange ELSE state - value END
$$ LANGUAGE SQL IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION union_intervals(token UUID, token2value regclass)
RETURNS datemultirange AS
$$
BEGIN
RETURN provenance_evaluate(
token,
token2value,
'{(,)}'::datemultirange,
'union_intervals_plus',
'union_intervals_times',
'union_intervals_monus');
END
$$ LANGUAGE plpgsql PARALLEL SAFE;
SELECT add_provenance('personnel_intervals');
SELECT create_provenance_mapping('time_validity','personnel_intervals','valid_time');
CREATE TABLE union_intervals_result AS
SELECT *,union_intervals(provenance(),'time_validity')
FROM (
SELECT DISTINCT P1.city
FROM personnel_intervals P1 JOIN personnel_intervals P2
ON P1.city = P2.city
WHERE P1.id < P2.id
) t;
SELECT remove_provenance('union_intervals_result');
SELECT * FROM union_intervals_result;
DROP TABLE union_intervals_result;
CREATE TABLE union_intervals_result AS
SELECT *,union_intervals(provenance(),'time_validity')
FROM (
SELECT DISTINCT city FROM personnel_intervals
EXCEPT
SELECT DISTINCT P1.city
FROM personnel_intervals P1 JOIN personnel_intervals P2
ON P1.city = P2.city
WHERE P1.city = P2.city AND P1.id < P2.id
) t;
SELECT remove_provenance('union_intervals_result');
SELECT * FROM union_intervals_result;
DROP TABLE union_intervals_result;