将 SELECT 语句中的“前一行”值与现有行值相加

adn*_*adn 9 postgresql select postgresql-9.3

我想将先前的值与该行中的现有值相加。

这是我的代码:

SELECT
    co.partner_id,
    to_char(co.date, 'DD') AS day,
    to_char(co.date, 'MM') AS month,
    to_char(co.date, 'YYYY') AS year,
    sum(col.qty * p.price) AS priceday
FROM
    order_detail col
    JOIN
ORDER co ON co.id = col.order_id
JOIN product p ON p.id = col.product_id
GROUP BY
    co.partner_id,
    to_char(co.date, 'MM'),
    to_char(co.date, 'YYYY'),
    to_char(co.date, 'DD')
Run Code Online (Sandbox Code Playgroud)

该代码变成这样:图像表

桌子应该是这样的: 图片

谢谢。

and*_*eim 11

您可以将窗口函数与 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;
Run Code Online (Sandbox Code Playgroud)

注意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;
Run Code Online (Sandbox Code Playgroud)

注意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;
Run Code Online (Sandbox Code Playgroud)


Nic*_*ick 2

这是您需要的示例(我希望如此):

test=# with nums(n) as (
  select z from generate_series(1, 10) as _(z)
)
select
  n,
  sum(n) over (order by n)
from nums;
 n  | sum
----+-----
  1 |   1
  2 |   3
  3 |   6
  4 |  10
  5 |  15
  6 |  21
  7 |  28
  8 |  36
  9 |  45
 10 |  55
(10 rows)
Run Code Online (Sandbox Code Playgroud)

它就是所谓的“窗口函数”,请参阅此处的文档: https: //www.postgresql.org/docs/current/static/tutorial-window.html