Created
October 17, 2018 13:15
-
-
Save mtarnovan/c5d2cd5d9a3a49bc040804cd69a91560 to your computer and use it in GitHub Desktop.
Postgres (date) range coverage function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE IF NOT EXISTS EXTENSION btree_gist; | |
CREATE TABLE split_vat ( | |
cif varchar, | |
interval daterange NOT NULL, | |
applies_split_vat boolean NOT NULL, | |
EXCLUDE USING | |
gist (interval WITH &&, cif WITH =) | |
); | |
insert into split_vat values('1', daterange('2017-12-15', '2017-12-30', '[]'), true); | |
insert into split_vat values('1', daterange('2018-02-15', '2018-03-15', '[]'), true); | |
CREATE OR REPLACE FUNCTION uncovered_split_vat(daterange default daterange('2017-09-01', current_date), varchar default null) | |
RETURNS TABLE(cif varchar, uncovered_ranges daterange) | |
AS $$ | |
WITH RECURSIVE calendar AS ( | |
SELECT | |
$1 AS left, | |
$1 AS center, | |
$1 AS right, | |
$2 AS cif | |
UNION | |
SELECT | |
CASE split_vat.interval && calendar.left | |
WHEN TRUE THEN daterange(lower(calendar.left), lower(split_vat.interval * calendar.left)) | |
ELSE daterange(lower(calendar.right), lower(split_vat.interval * calendar.right)) | |
END AS left, | |
CASE split_vat.interval && calendar.left | |
WHEN TRUE THEN split_vat.interval * calendar.left | |
ELSE split_vat.interval * calendar.right | |
END AS center, | |
CASE split_vat.interval && calendar.right | |
WHEN TRUE THEN daterange(upper(split_vat.interval * calendar.right), upper(calendar.right)) | |
ELSE daterange(upper(split_vat.interval * calendar.left), upper(calendar.left)) | |
END AS right, | |
split_vat.cif as cif | |
FROM calendar | |
JOIN split_vat ON | |
split_vat.interval && $1 AND | |
split_vat.interval <> calendar.center AND ( | |
split_vat.interval && calendar.left OR | |
split_vat.interval && calendar.right | |
) AND ($2 IS NULL OR split_vat.cif = $2) | |
) | |
SELECT * | |
FROM ( | |
SELECT | |
a.cif AS cif, | |
a.left AS uncovered_ranges | |
FROM calendar a | |
LEFT OUTER JOIN calendar b ON | |
a.left <> b.left AND | |
a.left @> b.left | |
GROUP BY a.left, a.cif | |
HAVING NOT bool_or(COALESCE(a.left @> b.left, FALSE)) | |
UNION | |
SELECT | |
a.cif AS cif, | |
a.right AS uncovered_ranges | |
FROM calendar a | |
LEFT OUTER JOIN calendar b ON | |
a.right <> b.right AND | |
a.right @> b.right | |
GROUP BY a.right, a.cif | |
HAVING NOT bool_or(COALESCE(a.right @> b.right, FALSE)) | |
) a | |
$$ LANGUAGE SQL STABLE; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment