加入并聚合右边的日期 table <= 左边的日期 table

Join and aggregate where date in right table <= date in left table

假设我有一个 table 有两列 - customer_iddate:

customer_id          date
          1    2020-01-29
          1    2020-03-14
          2    2020-04-05
          2    2020-02-18

我有另一个 table 显示客户购买的日期和金额:

customer_id          date    amount
          1    2019-12-03        10
          1    2020-01-30        20
          1    2020-03-10        30
          1    2020-03-18        40
          2    2020-02-29        50 
          2    2020-03-10        60
          2    2020-04-01        70

我现在想在第一个 table 和第二个 table 上创建一个新列,显示第一个 [= 的每一行上迄今为止购买金额的总和=28=]:

customer_id          date    amount_td
          1    2020-01-29           10
          1    2020-03-14           60
          2    2020-04-05          180
          2    2020-03-20          110    

我该怎么做?我对逻辑的最初想法是这样的:

SELECT
    table1.customer_id,
    table1.date,
    table2_agg as amount_td
FROM
    table1
LEFT JOIN (
    SELECT
        customer_id,
        SUM(amount)
    FROM
        table2
    HAVING
        table2.date <= table1.date
) table2_agg
ON
    table1.customer_id = table2_agg.customer_id

当然,这在句法和逻辑上并不完全存在。

由于需要根据 table1 中的 datetable2 中进行聚合,这可能比 JOIN 更容易编写为相关子查询:

SELECT
    table1.customer_id,
    table1.date,
    COALESCE((SELECT SUM(amount) AS amount 
              FROM table2
              WHERE table2.date <= table1.date AND
                    table2.customer_id = table1.customer_id), 0) AS amount
FROM
    table1

或者您可以将其写成 JOIN,但聚合需要发生在查询的顶层:

SELECT
    table1.customer_id,
    table1.date,
    COALESCE(SUM(table2.amount), 0) AS amount
FROM
    table1
LEFT JOIN 
    table2 ON table2.customer_id = table1.customer_id
          AND table2.date <= table1.date
GROUP BY table1.customer_id, table1.date

无论哪种情况,输出都是:

customer_id     date        amount
1               2020-01-29  10
1               2020-03-14  60
2               2020-04-05  180
2               2020-03-20  110

Demo on dbfiddle

如果您的(未公开的)DBMS 支持横向连接,您可以这样做:

select t1.*, t.amount
from table1 t1
  left join lateral (
     select t2.customer_id, sum(t2.amount) as amount
     from table2 t2
     where t2.customer_id = t1.customer_id
       and t2.date <= t1.date
     group by t2.customer_id
  ) as t on true

Online demo