Postgresql重叠日期范围和求和结果

时间:2017-07-09 20:14:37

标签: postgresql date join date-range

我正在尝试将合同表链接到交易列表,以查看是否存在任何超支,但是,数据没有有效的唯一共享密钥。

这是我的合约表的一个例子:

| buyer_id | supplier_id | start_date | end_date   | contract_value  |
| buyer_a  | supplier_a  | 2015-01-01 | 2017-01-01 | 240000          |
| buyer_a  | supplier_a  | 2016-01-01 | 2016-06-01 | 6000            |
| buyer_a  | supplier_b  | 2015-01-01 | 2015-12-31 | 100000          |
| buyer_a  | supplier_b  | 2017-01-01 | 2017-12-31 | 100000          |

这是我的消费表的一个例子:

| buyer_id | supplier_id | month      | trans_value    |
| buyer_a  | supplier_a  | 2015-01-01 | 1230.12        |
| buyer_a  | supplier_a  | 2015-02-01 | 1735.98        |
| buyer_a  | supplier_a  | 2015-03-01 | 2242.02        |

由于合约日期重叠(例如与supplier_a的合约),我不能只链接每份合约每个月的所有交易,因为这意味着我在此期间重复计算交易。交叠。

同样,我不能使用max()和min(),因为在合同之间发生的任何交易(例如那些与supplier_b的交易)都会被包括在内。

据我所知,链接这些表的最佳方法是将我的合约表汇总到一个视图中,以便它看起来像这样......

| buyer_id | supplier_id | month      | value |
| buyer_a  | supplier_a  | 2015-01-01 | 10000 |
| buyer_a  | supplier_a  | 2015-02-01 | 10000 |
| buyer_a  | supplier_a  | 2015-03-01 | 10000 |
| buyer_a  | supplier_a  | 2015-04-01 | 10000 |
| buyer_a  | supplier_a  | 2015-05-01 | 10000 |
| buyer_a  | supplier_a  | 2015-06-01 | 10000 |
| buyer_a  | supplier_a  | 2015-07-01 | 10000 |

只要每个月的值是合同的总和份额,就可以轻松地将buyer_idsupplier_idmonth唯一的三重列上的交易关联起来,然后我就可以确定任何超支。

问题在于我甚至无法开始研究如何构建新视图。我觉得我应该可以使用子查询来解包'将日期范围分为几个月的列表,然后是总和(case()),但我的深度不同。

PS。我无法控制这些数据的发布方式,因此无法从源头上改进数据。

编辑:我希望能够创建这样的输出,然后我可以将其放入图表中以显示超支:

| buyer_id | supplier_id | month      | monthly_con_val | trans_value |
| buyer_a  | supplier_a  | 2015-01-01 | 10000           | 34000       |
| buyer_a  | supplier_a  | 2015-02-01 | 10000           | 10000       |
| buyer_a  | supplier_a  | 2015-03-01 | 50000           | 8000        |
| buyer_a  | supplier_a  | 2015-04-01 | 50000           | 14000       |
| buyer_a  | supplier_a  | 2015-05-01 | 50000           | 4000        |
| buyer_a  | supplier_a  | 2015-06-01 | 10000           | 3000        |
| buyer_a  | supplier_a  | 2015-07-01 | 10000           | 3000        |

1 个答案:

答案 0 :(得分:1)

这样的东西
with
  -- Sample data
  contracts(bs_id, start_date, end_date, contract_value) as (values
    (1, '2015-01-01'::date, '2017-01-01'::date, 240000),
    (1, '2016-01-01'::date, '2016-06-01'::date, 6000)),
  spending(bs_id, month, trans_value) as (values
    (1, '2015-01-01'::date, 1230.12),
    (1, '2015-02-01'::date, 1735.98),
    (1, '2016-05-01'::date, 5689.01)),
  -- End of sample data
  contracts_monthly as (
    select
      bs_id,
      month::date,
      sum(
        contract_value / (
          (extract(year from end_date)*12 + extract(month from end_date)) - 
          (extract(year from start_date)*12 + extract(month from start_date)))) as monthly_con_val
    from contracts, generate_series(start_date, end_date, interval '1 month') as month
    group by bs_id, month
    order by bs_id, month)
select
  *
from
  contracts_monthly left join spending using (bs_id, month);

为了使示例更紧凑,我将列buyer_id | supplier_id合并到单个列bs_id中。

About generate_series() function