您可以使用带有 Frame 子句的窗口函数。
如果你想与上一行求和,那么你会这样做:
SELECT o.partner_id, o.date, SUM(SUM(p.price * od.qty)) OVER (PARTITION BY o.partner_id ORDER BY o.partner_id, o.date ROWS 1 PRECEDING) AS priceday
FROM test.order AS o
INNER JOIN test.order_detail AS od
ON o.id = od.order_id
INNER JOIN test.product AS p
ON od.product_id = p.id
GROUP BY o.partner_id, o.date;
注意ROWS 1 PRECEDING。
如果你想对所有前面的行求和(运行总计),那么你会这样做:
SELECT o.partner_id, o.date, SUM(SUM(p.price * od.qty)) OVER (PARTITION BY o.partner_id ORDER BY o.partner_id, o.date ROWS UNBOUNDED PRECEDING) AS priceday
FROM test.order AS o
INNER JOIN test.order_detail AS od
ON o.id = od.order_id
INNER JOIN test.product AS p
ON od.product_id = p.id
GROUP BY o.partner_id, o.date;
注意ROWS UNBOUNDED PRECEDING。
说明
SUM(SUM(p.price * od.qty)) OVER (PARTITION BY o.partner_id ORDER BY o.partner_id, o.date ROWS 1 PRECEDING) AS priceday是主角:
-
SUM(p.price * od.qty) - 计算每天的价格
-
SUM(SUM(...)) OVER (...) - 对多天的多个价格求和
-
PARTITION BY o.partner_id - 需要将 SUM 保持在 partner_id 的边界内
-
ORDER BY o.partner_id, o.date - 需要按日期对分区中的行进行排序
-
ROWS 1 PRECEDING - 为了将前一行与当前行一起包含在 SUM 中
完整示例(便于测试)
CREATE SCHEMA test;
CREATE TABLE test.order (
id SERIAL PRIMARY KEY,
partner_id int,
date date
);
CREATE TABLE test.product (
id SERIAL PRIMARY KEY,
price DECIMAL
);
CREATE TABLE test.order_detail (
id SERIAL PRIMARY KEY,
order_id int REFERENCES test.order (id),
product_id int REFERENCES test.product (id),
qty int
);
INSERT INTO test.order
(partner_id, date)
VALUES
(531, '2017-06-20'),
(531, '2017-06-21'),
(531, '2017-06-22'),
(532, '2017-06-20'),
(532, '2017-06-20'),
(532, '2017-06-22'),
(532, '2017-06-23');
INSERT INTO test.product
(price)
VALUES
(1000.0);
INSERT INTO test.order_detail
(order_id, product_id, qty)
VALUES
(1, 1, 300),
(2, 1, 230),
(3, 1, 130),
(4, 1, 300),
(5, 1, 230),
(6, 1, 130),
(7, 1, 100);
-- sum with the previous row
SELECT o.partner_id, o.date, SUM(SUM(p.price * od.qty)) OVER (PARTITION BY o.partner_id ORDER BY o.partner_id, o.date ROWS 1 PRECEDING) AS priceday
FROM test.order AS o
INNER JOIN test.order_detail AS od
ON o.id = od.order_id
INNER JOIN test.product AS p
ON od.product_id = p.id
GROUP BY o.partner_id, o.date;
-- sum with all the previous rows
SELECT o.partner_id, o.date, SUM(SUM(p.price * od.qty)) OVER (PARTITION BY o.partner_id ORDER BY o.partner_id, o.date ROWS UNBOUNDED PRECEDING) AS priceday
FROM test.order AS o
INNER JOIN test.order_detail AS od
ON o.id = od.order_id
INNER JOIN test.product AS p
ON od.product_id = p.id
GROUP BY o.partner_id, o.date;
DROP SCHEMA test CASCADE;