-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpostgres-init-datm-query-diff.sql
240 lines (234 loc) · 6.21 KB
/
postgres-init-datm-query-diff.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/**
* Find stream datum records for calculating the difference between two dates within a time
* tolerance.
*
* @param sid the stream id
* @param start_ts the minimum date (inclusive)
* @param end_ts the maximum date (exclusive)
* @param tolerance the maximum time to look forward/backward for adjacent data
*/
CREATE OR REPLACE FUNCTION solardatm.find_datm_diff_near_rows(
sid UUID,
start_ts TIMESTAMP WITH TIME ZONE,
end_ts TIMESTAMP WITH TIME ZONE,
tolerance INTERVAL DEFAULT INTERVAL '3 months'
) RETURNS SETOF solardatm.datm_rec LANGUAGE SQL STABLE ROWS 10 AS
$$
-- choose earliest first/last rows for start/end dates, which may be exact time matches
WITH d AS (
(
SELECT d.*, 0::SMALLINT AS rtype
FROM solardatm.find_datm_around(sid, start_ts, tolerance, TRUE) AS d
ORDER BY d.ts
LIMIT 1
)
UNION
(
SELECT d.*, 0::SMALLINT AS rtype
FROM solardatm.find_datm_around(sid, end_ts, tolerance, TRUE) AS d
ORDER BY d.ts
LIMIT 1
)
)
, drange AS (
SELECT
COALESCE(min(ts), start_ts) AS ts_min
, COALESCE(max(ts), end_ts) AS ts_max
FROM d
)
, resets AS (
SELECT
aux.stream_id
, aux.ts
, aux.data_a
, aux.rtype AS rtype
FROM drange, solardatm.find_datm_aux_for_time_span(
sid,
LEAST(drange.ts_min, start_ts),
GREATEST(drange.ts_max, end_ts)
) aux
)
-- find min, max ts out of raw + resets to eliminate extra leading/trailing from combined results
, ts_range AS (
SELECT min_ts, max_ts
FROM (
SELECT COALESCE(max(ts), start_ts) AS min_ts
FROM (
SELECT max(ts) FROM d WHERE ts <= start_ts
UNION ALL
SELECT max(ts) FROM resets WHERE ts <= start_ts
) l(ts)
) min, (
SELECT COALESCE(max(ts), end_ts) AS max_ts
FROM (
SELECT max(ts) FROM d WHERE ts <= end_ts
UNION ALL
SELECT max(ts) FROM resets WHERE ts <= end_ts
) r(ts)
) max
)
-- combine raw datm with reset datm
SELECT d.stream_id
, d.ts
, NULL::NUMERIC[] AS data_i
, d.data_a
, NULL::TEXT[] AS data_s
, NULL::TEXT[] AS data_t
, d.rtype
FROM d, ts_range
WHERE d.ts >= ts_range.min_ts AND d.ts <= ts_range.max_ts
UNION ALL
SELECT resets.stream_id
, resets.ts
, NULL::NUMERIC[] AS data_i
, resets.data_a
, NULL::TEXT[] AS data_s
, NULL::TEXT[] AS data_t
, resets.rtype
FROM resets, ts_range
WHERE resets.ts >= ts_range.min_ts
-- exclude any reading start record at exactly the end date
AND (resets.ts < end_ts OR resets.rtype < 2)
$$;
/**
* Find stream datum records for calculating the difference between two dates.
*
* @param sid the stream id
* @param start_ts the minimum date (inclusive)
* @param end_ts the maximum date (exclusive)
*/
CREATE OR REPLACE FUNCTION solardatm.find_datm_diff_rows(
sid UUID,
start_ts TIMESTAMP WITH TIME ZONE,
end_ts TIMESTAMP WITH TIME ZONE
) RETURNS SETOF solardatm.datm_rec LANGUAGE SQL STABLE ROWS 10 AS
$$
-- we just set a large tolerance for this query
SELECT * FROM solardatm.find_datm_diff_near_rows(sid, start_ts, end_ts, INTERVAL 'P1Y')
$$;
/**
* Find stream datum records for calculating the difference within two dates.
*
* @param sid the stream id
* @param start_ts the minimum date (inclusive)
* @param end_ts the maximum date (inclusive)
*/
CREATE OR REPLACE FUNCTION solardatm.find_datm_diff_within_rows(
sid UUID,
start_ts TIMESTAMP WITH TIME ZONE,
end_ts TIMESTAMP WITH TIME ZONE
) RETURNS SETOF solardatm.datm_rec LANGUAGE SQL STABLE ROWS 10 AS
$$
WITH d AS (
-- next after start
(
SELECT d.*, 0::SMALLINT AS rtype
FROM solardatm.da_datm d
WHERE d.stream_id = sid
AND d.ts >= start_ts
AND d.ts < end_ts
AND d.data_a IS NOT NULL
ORDER BY d.stream_id, d.ts
LIMIT 1
)
UNION
-- prev before end
(
SELECT d.*, 0::SMALLINT AS rtype
FROM solardatm.da_datm d
WHERE d.stream_id = sid
AND d.ts > start_ts
AND d.ts <= end_ts
AND d.data_a IS NOT NULL
ORDER BY d.stream_id, d.ts DESC
LIMIT 1
)
)
, resets AS (
SELECT
aux.stream_id
, aux.ts
, aux.data_a
, aux.rtype AS rtype
FROM solardatm.find_datm_aux_for_time_span(
sid,
start_ts,
end_ts
) aux
)
-- find min, max ts out of raw + resets to eliminate extra leading/trailing from combined results
, ts_range AS (
SELECT min_ts, max_ts
FROM (
SELECT COALESCE(max(ts), start_ts) AS min_ts
FROM (
SELECT max(ts) FROM d WHERE ts < start_ts
UNION ALL
SELECT max(ts) FROM resets WHERE ts <= start_ts
) l(ts)
) min, (
SELECT COALESCE(max(ts), end_ts) AS max_ts
FROM (
SELECT max(ts) FROM d WHERE ts < end_ts
UNION ALL
SELECT max(ts) FROM resets WHERE ts <= end_ts
) r(ts)
) max
)
-- combine raw datm with reset datm
SELECT d.stream_id
, d.ts
, NULL::NUMERIC[] AS data_i
, d.data_a
, NULL::TEXT[] AS data_s
, NULL::TEXT[] AS data_t
, d.rtype
FROM d, ts_range
WHERE d.ts >= ts_range.min_ts AND d.ts <= ts_range.max_ts
UNION ALL
SELECT resets.stream_id
, resets.ts
, NULL::NUMERIC[] AS data_i
, resets.data_a
, NULL::TEXT[] AS data_s
, NULL::TEXT[] AS data_t
, resets.rtype
FROM resets, ts_range
WHERE resets.ts >= ts_range.min_ts
-- exclude any reading start record at exactly the end date
AND (resets.ts < end_ts OR resets.rtype < 2)
$$;
/**
* Find stream datum records for calculating the difference between two exact dates.
*
* @param sid the stream id
* @param start_ts the minimum date (exact)
* @param end_ts the maximum date (exact)
* @param tolerance the maximum time to look forward/backward for adjacent data
*/
CREATE OR REPLACE FUNCTION solardatm.find_datm_diff_at_rows(
sid UUID,
start_ts TIMESTAMP WITH TIME ZONE,
end_ts TIMESTAMP WITH TIME ZONE,
tolerance INTERVAL DEFAULT INTERVAL '3 months'
) RETURNS SETOF solardatm.datm_rec LANGUAGE SQL STABLE ROWS 10 AS
$$
WITH d AS (
SELECT (solardatm.calc_datm_at(d, start_ts)).*
FROM solardatm.find_datm_around(sid, start_ts, tolerance) d
HAVING count(*) > 0
UNION
SELECT (solardatm.calc_datm_at(d, end_ts)).*
FROM solardatm.find_datm_around(sid, end_ts, tolerance) d
HAVING count(*) > 0
)
-- combine raw datm with reset datm
SELECT d.stream_id
, d.ts
, d.data_i
, d.data_a
, d.data_s
, d.data_t
, 0::SMALLINT AS rtype
FROM d
$$;