使用条件和分组依据查找累计总数
Finding cumulative totals with condition and group by
这是我的案例:
我想计算给定商品在任何给定日期的数量和价格。
价格是根据商品总数量和单价计算得出的,因此价格会根据商品的数量而变化。
warehouse_1
表示该项目是从该仓库发货的,warehouse_2
表示该项目已发送到该仓库。
这是我的逻辑:
获取每个项目的交付并计算它们的数量。 (第一个 CTE)
分别求出两个仓库的数量总和。 (第二届 CTE)
计算最终数量并将其乘以单价。
显示由商品编号、数量和价格组成的结果。
我编写了一个可以正确计算的查询,但是当数据量变大时,它的速度会呈指数级下降。 (在我的 6k 行数据库上花费 5 秒,几乎锁定了我同事的 21k 行数据库上的数据库)
如何优化此查询?我正在对来自第一个 CTE 的每一行的第二个 CTE 进行累积计算,我认为这需要返工。
我可以用吗
LAG()
这个用例的功能?我用
之类的东西试过了
LAG(a.deliveryTotal) over(order by a.updated desc rows between unbounded preceding and current row)
而不是第二个 CTE 中的 CASE 块,但我似乎无法弄清楚如何使用 filter()
或在 LAG() 语句中放置条件。
这是我的查询:
`
with deliveriesCTE as (
select
row_number() over(partition by it.id
order by
dd.updated asc) as rn,
sum(dd.quantity) as deliveryTotal,
dd.updated as updated,
it.id as item_id,
d.warehouse_1 as outWH,
d.warehouse_2 as inWH,
d.company_code as company
from
deliveries d
join deliveries_detail dd on
dd.deliveries_id = d.id
join items it on
it.id = dd.item_id
where
...
group by
dd.updated,
it.id,
d.warehouse_1,
d.warehouse_2,
d.company_code
order by
dd.updated asc),
cumulativeTotalsByUnit as (
select
distinct on
(a.item_id) a.rn,
a.deliveryTotal,
a.updated,
a.item_id,
a.outWH,
a.inWH,
a.company,
case
when a.rn = 1
and a.outWH is not null then coalesce(a.deliveryTotal,
0)
else (
select
coalesce(sum(b.deliveryTotal) filter(
where b.outWH is not null),
0)
from
deliveriesCTE b
where
a.item_id = b.item_id
and b.rn <= a.rn)
end as outWHTotal,
case
when a.rn = 1
and a.inWH is not null then coalesce(a.deliveryTotal,
0)
else (
select
coalesce(sum(b.deliveryTotal) filter(
where b.inWH is not null),
0)
from
deliveriesCTE b
where
a.item_id = b.item_id
and b.rn <= a.rn)
end as inWHTotal
from
deliveriesCTE a
order by
a.item_id,
a.updated desc)
select
resultView.item_id,
resultView.quantity,
resultView.price
from
(
select
cumTotals.item_id,
cumTotals.inWHTotal - cumTotals.outWHTotal as quantity,
p.price * (cumTotals.inWHTotal - cumTotals.outWHTotal) as price
from
prices p
join cumulativeTotalsByUnit cumTotals on
cumTotals.item_id = p.item_id ) resultView
where
resultView.rn = 1;
`
很难说没有 MCV, but my guess on what you are trying to do is do a Windowed SUM() calculation as opposed to LAG(). There is documentation Here 就可以使用。
查询 cumulativeTotalsByUnit
应该不是必需的,并且很可能是二次查询来执行复杂的自引用连接。
您的交付 CTE 应如下所示:
select
sum(dd.quantity) over (partition by it.id ORDER BY dd.updated asc) as deliveryTotal,
dd.updated as updated,
it.id as item_id,
d.warehouse_1 as outWH,
d.warehouse_2 as inWH,
d.company_code as company
from
deliveries d
join deliveries_detail dd on
dd.deliveries_id = d.id
join items it on
it.id = dd.item_id
where
...
group by
dd.updated,
it.id,
d.warehouse_1,
d.warehouse_2,
d.company_code
order by
dd.updated asc
这是我的案例:
我想计算给定商品在任何给定日期的数量和价格。
价格是根据商品总数量和单价计算得出的,因此价格会根据商品的数量而变化。
warehouse_1
表示该项目是从该仓库发货的,warehouse_2
表示该项目已发送到该仓库。
这是我的逻辑:
获取每个项目的交付并计算它们的数量。 (第一个 CTE)
分别求出两个仓库的数量总和。 (第二届 CTE)
计算最终数量并将其乘以单价。
显示由商品编号、数量和价格组成的结果。
我编写了一个可以正确计算的查询,但是当数据量变大时,它的速度会呈指数级下降。 (在我的 6k 行数据库上花费 5 秒,几乎锁定了我同事的 21k 行数据库上的数据库)
如何优化此查询?我正在对来自第一个 CTE 的每一行的第二个 CTE 进行累积计算,我认为这需要返工。
我可以用吗
LAG()
这个用例的功能?我用
LAG(a.deliveryTotal) over(order by a.updated desc rows between unbounded preceding and current row)
而不是第二个 CTE 中的 CASE 块,但我似乎无法弄清楚如何使用 filter()
或在 LAG() 语句中放置条件。
这是我的查询:
`
with deliveriesCTE as (
select
row_number() over(partition by it.id
order by
dd.updated asc) as rn,
sum(dd.quantity) as deliveryTotal,
dd.updated as updated,
it.id as item_id,
d.warehouse_1 as outWH,
d.warehouse_2 as inWH,
d.company_code as company
from
deliveries d
join deliveries_detail dd on
dd.deliveries_id = d.id
join items it on
it.id = dd.item_id
where
...
group by
dd.updated,
it.id,
d.warehouse_1,
d.warehouse_2,
d.company_code
order by
dd.updated asc),
cumulativeTotalsByUnit as (
select
distinct on
(a.item_id) a.rn,
a.deliveryTotal,
a.updated,
a.item_id,
a.outWH,
a.inWH,
a.company,
case
when a.rn = 1
and a.outWH is not null then coalesce(a.deliveryTotal,
0)
else (
select
coalesce(sum(b.deliveryTotal) filter(
where b.outWH is not null),
0)
from
deliveriesCTE b
where
a.item_id = b.item_id
and b.rn <= a.rn)
end as outWHTotal,
case
when a.rn = 1
and a.inWH is not null then coalesce(a.deliveryTotal,
0)
else (
select
coalesce(sum(b.deliveryTotal) filter(
where b.inWH is not null),
0)
from
deliveriesCTE b
where
a.item_id = b.item_id
and b.rn <= a.rn)
end as inWHTotal
from
deliveriesCTE a
order by
a.item_id,
a.updated desc)
select
resultView.item_id,
resultView.quantity,
resultView.price
from
(
select
cumTotals.item_id,
cumTotals.inWHTotal - cumTotals.outWHTotal as quantity,
p.price * (cumTotals.inWHTotal - cumTotals.outWHTotal) as price
from
prices p
join cumulativeTotalsByUnit cumTotals on
cumTotals.item_id = p.item_id ) resultView
where
resultView.rn = 1;
`
很难说没有 MCV, but my guess on what you are trying to do is do a Windowed SUM() calculation as opposed to LAG(). There is documentation Here 就可以使用。
查询 cumulativeTotalsByUnit
应该不是必需的,并且很可能是二次查询来执行复杂的自引用连接。
您的交付 CTE 应如下所示:
select
sum(dd.quantity) over (partition by it.id ORDER BY dd.updated asc) as deliveryTotal,
dd.updated as updated,
it.id as item_id,
d.warehouse_1 as outWH,
d.warehouse_2 as inWH,
d.company_code as company
from
deliveries d
join deliveries_detail dd on
dd.deliveries_id = d.id
join items it on
it.id = dd.item_id
where
...
group by
dd.updated,
it.id,
d.warehouse_1,
d.warehouse_2,
d.company_code
order by
dd.updated asc