【问题标题】:Group by dynamic time period按动态时间段分组
【发布时间】:2017-04-06 22:20:23
【问题描述】:

对于我的问题,我将尝试创建一个简化的示例。
表“订单”:

ID |    date    | client | product | product_limit_period (in months)
1  | 2015-01-01 | Bob    | table   | 1
2  | 2015-01-31 | Bob    | table   | 1
3  | 2015-02-01 | Bob    | table   | 1
4  | 2015-01-01 | Mary   | lamb    | 12
5  | 2015-06-01 | Mary   | lamb    | 12
6  | 2016-01-01 | Mary   | lamb    | 12
7  | 2016-12-31 | Mary   | lamb    | 12

这是结果,我想得到:

client | product | group | count
Bob    | table   | 1     | 2       #ID 1, 2
Bob    | table   | 2     | 1       #ID 3
Mary   | lamb    | 3     | 2       #ID 4, 5
Mary   | lamb    | 4     | 2       #ID 6, 7

每个产品都有一个限制和一个限制期(以月为单位)。我需要能够查看在特定时期内是否有任何客户订购了超过其限制的产品。 以月为单位的期间可能是 1 个月或以月为单位的几年。 期间可能是 1 个月、12 个月、24 个月……直到 108 个月(9 年)。 p>

我觉得我需要使用一些窗口函数和分组依据的组合。但我还没弄清楚怎么做。

我正在使用 postgres 9.1。如果我需要提供更多信息,请告诉我。

感谢任何帮助,即使只是指出我正确的方向!

编辑:
澄清分组的工作原理: 限制期从第一个订单开始。 Bob 的第一个订单是 2015-01-01,因此此期间以 2015-01-31 结束。 2015-02-01 开始第二个时期。 一个时期总是从一个月的第一天开始,到一个月的最后一天结束。

【问题讨论】:

  • 为什么你将#ID 1, 2 组合在一起,而不是#ID 2, 3? 2 和 3 也有小于月的差异。如果你想找到不同的组,你会很难。相反,请用limit 列描述product 表。只找到那些违反限制的人(但没有不同的组)很容易。
  • 限时从第一个订单开始。 Bob 的第一个订单是 2015-01-01,因此此期间以 2015-01-31 结束。 2015-02-01 开始第二个时期。一个时期总是从一个月的第一天开始,到一个月的最后一天结束。我也会在我的问题中添加这个,谢谢!
  • 所以,如果第一个订单是在2015-03-15 上,而product_limit_period12(或超过一年),那么这个时期仍然从实际 ? (在我的示例中为2015-03-01)。
  • @pozs 是的,你是对的!

标签: sql postgresql


【解决方案1】:

无需复杂化窗口和分组依据,只需将case 添加到窗口或组,如下所示:

t=# select
  client
, product
, count(1)
, string_agg(id::text,',')
from so44
group by
  client
, product
, date_trunc(case when product_limit_period = 1 then 'month' else 'year' end,date);
  client  |  product  | count | string_agg
----------+-----------+-------+------------
  Bob     |  table    |     2 | 1,2
  Bob     |  table    |     1 | 3
  Mary    |  lamb     |     2 | 4,5
  Mary    |  lamb     |     2 | 6,7
(4 rows)

样本:

t=# create table so44 (i int,"date" date,client text,product text,product_limit_period int);
CREATE TABLE
t=# copy so44 from stdin delimiter '|';
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> 1  | 2015-01-01 | Bob    | table   | 1
>> 2  | 2015-01-31 | Bob    | table   | 1
3  | 2015-02-01 | Bob    | table   | 1
4  | 2015-01-01 | Mary   | lamb    | 12
5  | 2015-06-01 | Mary   | lamb    | 12
6  | 2016-01-01 | Mary   | lamb    | 12
7  | 2016-12-31 | Mary   | lamb    | 12>> >> >> >> >>
>> \.
COPY 7

【讨论】:

  • 嗯,好的。但是如果这个期限是几年呢。目前我的系统允许 1 个月、12 个月、24 个月……直到 108 个月(9 年)
  • 我相信你应该在人们试图帮助你之前在你的问题中说明这一点:)
  • 在我的问题中,我说“几个月的时间可能是 1 个月或几个月的几年。”。如果写得容易被遗漏,我很抱歉。我将编辑我的问题并以粗体显示。感谢您的帮助 - 此解决方案可以用于两个以上的不同时期吗?
  • 并回答您的通知 - 逻辑不会改变 - 您必须像我对 case 所做的那样进行人工比较列。顺便说一句,如果您可以影响流程,我会选择两列 - startdate 和 endate 来比较
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 2015-12-19
  • 1970-01-01
  • 2017-10-26
  • 2019-09-03
相关资源
最近更新 更多