在 window 的最大时间段内聚合(SUM 或 AVG)
Aggregate(SUM or AVG) over a window for max time period
我有一个 INPUT table,如下所示。我想计算 2 个指标:
sellthru = sum(qty sold over 4 weeks) / initial stock at the beginning of the 4-week period x 100
coverage = stock at the end of the 4-week period / AVG(qty sold over 4 weeks) / x 100
输出 table 应该只显示给定条形码的最大周数。
我试过使用 window 函数执行此操作,但只能设法获得滚动值。
sum(quantity) over (partition by barcode order by SUM(week_number) ROWS BETWEEN 4 PRECEDING AND 1 PRECEDING)/NULLIF(sum(stock),0)::decimal
--Code to create the table:
CREATE TABLE sell ( week_number int, barcode int, quantity int, stock int );
-- Insert values
insert into sell values (1,222,3,2); insert into sell values (2,222,1,0); insert into sell values (3,222,2,3); insert into sell values (4,222,2,1); insert into sell values (5,222,2,2); insert into sell values (6,222,2,2); insert into sell values (1,333,4,10); insert into sell values (2,333,5,2); insert into sell values (3,333,1,3); insert into sell values (4,333,0,4);
根据条件使用子查询和不同的 window 函数/分析函数以获得预期输出。
-- PostgreSQL(v11)
SELECT tt.week_number, tt.barcode
, ((tt.total_qty :: decimal(10, 2) / tt.min_stock :: decimal(10, 2)) * 100) :: decimal(10, 2) sellthru
, ((tt.max_stock :: decimal(10, 2) / tt.avg_qty :: decimal(10, 2)) * 100) :: decimal(10, 2) coverage
FROM (SELECT t.week_number, t.barcode, t.row_num
, SUM(quantity) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) total_qty
, AVG(quantity) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) avg_qty
, FIRST_VALUE(stock) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) max_stock
, LAST_VALUE(stock) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) min_stock
FROM (SELECT *
, ROW_NUMBER() OVER (PARTITION BY barcode ORDER BY week_number DESC) row_num
FROM sell) t
WHERE t.row_num <= 4) tt
WHERE tt.row_num = 1
使用多个 CTE 的另一种方法
-- PostgreSQL (v11)
WITH cte AS (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY barcode ORDER BY week_number DESC) row_num
FROM sell
), cte_1 AS (
SELECT week_number, barcode, row_num
, SUM(quantity) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) total_qty
, AVG(quantity) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) avg_qty
, FIRST_VALUE(stock) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) max_stock
, LAST_VALUE(stock) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) min_stock
FROM cte
WHERE row_num <= 4
)
SELECT week_number, barcode
, ((total_qty :: decimal(10, 2) / min_stock :: decimal(10, 2)) * 100) :: decimal(10, 2) sellthru
, ((max_stock :: decimal(10, 2) / avg_qty :: decimal(10, 2)) * 100) :: decimal(10, 2) coverage
FROM cte_1
WHERE row_num = 1
请检查url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=5aa32e2e8f80be713774fc3ee761c2be
N.B.: 如果将来考虑 week_number = 5 或任何数字,则使用 row_num <= 5 或该数字代替共 row_num <= 4
我有一个 INPUT table,如下所示。我想计算 2 个指标:
sellthru = sum(qty sold over 4 weeks) / initial stock at the beginning of the 4-week period x 100
coverage = stock at the end of the 4-week period / AVG(qty sold over 4 weeks) / x 100
输出 table 应该只显示给定条形码的最大周数。
我试过使用 window 函数执行此操作,但只能设法获得滚动值。
sum(quantity) over (partition by barcode order by SUM(week_number) ROWS BETWEEN 4 PRECEDING AND 1 PRECEDING)/NULLIF(sum(stock),0)::decimal
--Code to create the table:
CREATE TABLE sell ( week_number int, barcode int, quantity int, stock int );
-- Insert values
insert into sell values (1,222,3,2); insert into sell values (2,222,1,0); insert into sell values (3,222,2,3); insert into sell values (4,222,2,1); insert into sell values (5,222,2,2); insert into sell values (6,222,2,2); insert into sell values (1,333,4,10); insert into sell values (2,333,5,2); insert into sell values (3,333,1,3); insert into sell values (4,333,0,4);
根据条件使用子查询和不同的 window 函数/分析函数以获得预期输出。
-- PostgreSQL(v11)
SELECT tt.week_number, tt.barcode
, ((tt.total_qty :: decimal(10, 2) / tt.min_stock :: decimal(10, 2)) * 100) :: decimal(10, 2) sellthru
, ((tt.max_stock :: decimal(10, 2) / tt.avg_qty :: decimal(10, 2)) * 100) :: decimal(10, 2) coverage
FROM (SELECT t.week_number, t.barcode, t.row_num
, SUM(quantity) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) total_qty
, AVG(quantity) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) avg_qty
, FIRST_VALUE(stock) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) max_stock
, LAST_VALUE(stock) OVER (PARTITION BY t.barcode ORDER BY t.row_num rows between current row and unbounded following) min_stock
FROM (SELECT *
, ROW_NUMBER() OVER (PARTITION BY barcode ORDER BY week_number DESC) row_num
FROM sell) t
WHERE t.row_num <= 4) tt
WHERE tt.row_num = 1
使用多个 CTE 的另一种方法
-- PostgreSQL (v11)
WITH cte AS (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY barcode ORDER BY week_number DESC) row_num
FROM sell
), cte_1 AS (
SELECT week_number, barcode, row_num
, SUM(quantity) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) total_qty
, AVG(quantity) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) avg_qty
, FIRST_VALUE(stock) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) max_stock
, LAST_VALUE(stock) OVER (PARTITION BY barcode ORDER BY row_num rows between current row and unbounded following) min_stock
FROM cte
WHERE row_num <= 4
)
SELECT week_number, barcode
, ((total_qty :: decimal(10, 2) / min_stock :: decimal(10, 2)) * 100) :: decimal(10, 2) sellthru
, ((max_stock :: decimal(10, 2) / avg_qty :: decimal(10, 2)) * 100) :: decimal(10, 2) coverage
FROM cte_1
WHERE row_num = 1
请检查url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=5aa32e2e8f80be713774fc3ee761c2be
N.B.: 如果将来考虑 week_number = 5 或任何数字,则使用 row_num <= 5 或该数字代替共 row_num <= 4