我目前有以下查询:
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
FROM inventory_resupplylogiteminstance a
INNER JOIN inventory_resupplylog b ON b.uid = a.fk_resupply_log_id
)
SELECT a.name,
SUM(CASE WHEN b.date < ('2018-10-10'::date) THEN b.absquantity END) as starting_balance,
SUM(CASE WHEN b.date > ('2018-10-10'::date) AND b.date < ('2018-10-12'::date) AND b.movement = 'aa' THEN b.absquantity END) as aa,
SUM(CASE WHEN b.date > ('2018-10-10'::date) AND b.date < ('2018-10-12'::date) AND b.movement = 'bb' THEN b.absquantity END) as bb,
SUM(CASE WHEN b.date > ('2018-10-10'::date) AND b.date < ('2018-10-12'::date) AND b.movement = 'cc' THEN b.absquantity END) as cc,
SUM(CASE WHEN b.date > ('2018-10-10'::date) AND b.date < ('2018-10-12'::date) AND b.movement = 'dd' THEN b.absquantity END) as dd,
SUM(CASE WHEN b.date < ('2018-10-12'::date) THEN b.absquantity END) 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
如您所见,第2-5行SUM行是多余的,因为它们正在查询b.date
与2018-10-10
之间的行。有什么方法可以重写我的查询,以便只写一次2018-10-12
并仍然能够在同一行上选择b.date > ('2018-10-10'::date) AND b.date < ('2018-10-12'::date)
和starting_balance
?
答案 0 :(得分:2)
您可以检查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的range functions:< / p>
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, '()')
创建一个date range,其中两个日期被排除。
<@
运算符测试日期是否在给定范围内。
因此,表达式b.date <@ b.check_range
与b.date > '2018-10-10'::date AND b.date < '2018-10-12'::date
等效(因为定义的范围不包括边缘)