【问题标题】:Postgresql overlapping date ranges and summing resultsPostgresql 重叠日期范围和求和结果
【发布时间】:2017-07-09 20:14:36
【问题描述】:

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

这是我的合同表的示例:

| 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        |

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

同样,我不能使用 max() 和 min(),因为在合同之间发生的任何交易(例如带有供应商_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 这三个唯一列上的交易联系起来,然后我可以识别任何超支。

问题是我什至无法开始弄清楚如何构建新视图。我觉得我应该能够使用子查询将日期范围“解压缩”到月份列表中,然后使用 sum(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        |

【问题讨论】:

  • 你能提供你想要得到的结果的例子吗?

标签: postgresql date join date-range


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多