Вы можете проверить диапазон в CTE и создать флаг, который указывает, находится ли строка в указанном диапазоне.
Затем вы можете использовать этот флаг в последнем SELECT.Переключение на выражение FILTER ()
также делает его более читабельным:
WITH instances AS (
SELECT b.ldtc as date,
a.fk_item_id,
b.movement,
a.quantity,
CASE
WHEN b.movement = 'Inbound' THEN a.quantity
ELSE -a.quantity
END as absquantity,
-- the column in_range returns either true or false
(b.ldtc > ('2018-10-10'::date) AND b.date < ('2018-10-12'::date)) as in_range
FROM inventory_resupplylogiteminstance a
INNER JOIN inventory_resupplylog b ON b.uid = a.fk_resupply_log_id
)
SELECT a.name,
SUM(b.absquantity) filter (where b.date < '2018-10-10'::date) as starting_balance,
SUM(b.absquantity) filter (where in_range and b.movement = 'aa') as aa,
SUM(b.absquantity) filter (where in_range and b.movement = 'bb') as bb,
SUM(b.absquantity) filter (where in_range and b.movement = 'cc') as cc,
SUM(b.absquantity) filter (where in_range and b.movement = 'dd') as dd,
SUM(b.absquantity) filter (where b.date < '2018-10-12'::date) AS ending_balance
FROM inventory_item a
LEFT JOIN instances b ON b.fk_item_id = a.uid
GROUP BY a.uid, a.name
ORDER BY a.name;
Если вы не хотите повторять дату для начального и конечного баланса, вы можете указать диапазон, для которого вы хотите проверитьв CTE, затем используйте функции диапазона Postgres в конечном запросе:
WITH instances AS (
SELECT b.ldtc as date,
a.fk_item_id,
b.movement,
a.quantity,
CASE
WHEN b.movement = 'Inbound' THEN a.quantity
ELSE -a.quantity
END as absquantity,
daterange('2018-10-10'::date, '2018-10-12'::date, '()') as check_range
FROM inventory_resupplylogiteminstance a
INNER JOIN inventory_resupplylog b ON b.uid = a.fk_resupply_log_id
)
SELECT a.name,
SUM(b.absquantity) filter (where b.date < lower(check_range)) as starting_balance,
SUM(b.absquantity) filter (where b.date <@ b.check_range and b.movement = 'aa') as aa,
SUM(b.absquantity) filter (where b.date <@ b.check_range and b.movement = 'bb') as bb,
SUM(b.absquantity) filter (where b.date <@ b.check_range and b.movement = 'cc') as cc,
SUM(b.absquantity) filter (where b.date <@ b.check_range and b.movement = 'dd') as dd,
SUM(b.absquantity) filter (where b.date < upper(b.check_range))) AS ending_balance
FROM inventory_item a
LEFT JOIN instances b ON b.fk_item_id = a.uid
GROUP BY a.uid, a.name
ORDER BY a.name;
daterange('2018-10-10'::date, '2018-10-12'::date, '()')
создает диапазон дат , где две даты исключен .
Оператор <@
проверяет, попадает ли дата в указанный диапазон.
Таким образом, выражение b.date <@ b.check_range
эквивалентно b.date > '2018-10-10'::date AND b.date < '2018-10-12'::date
(поскольку диапазон был определен без учета ребер)