使用date_trunc(Postgres 9.5.1)以默认选项以外的单位截断日期

时间:2016-10-31 05:47:36

标签: postgresql

我想知道除了使用date_trunc使用默认选项之外是否可以截断日期。例如,如果我有一个看起来像这样的表

date            dollars
2016-10-03        1
2016-10-05        1
2016-10-10        1
2016-10-17        2
2016-10-24        2

并说我想在每个“双周”期间截断和分组(所以在这个例子中,两个时间段,一个从2016-10-03开始,另一个从2016-10-17开始)。

我希望结果是

date            dollars
2016-10-03        3
2016-10-17        4

我该怎么做?我知道date_trunc我可以做date_trunc('week', date)之类的事情,但如果我想每两周做一次怎么办?或者如果我想使用其他自定义日期范围怎么办?

2 个答案:

答案 0 :(得分:5)

我相信无法仅使用一个内置函数来执行此操作。但是,有多种方法可以将它们结合使用。

要输出与您请求相同的结果,可以使用以下查询:

SELECT TO_DATE(
               CONCAT(
                  DATE_PART('YEAR', date),
                  (DATE_PART('WEEK', date)::INTEGER / 2) * 2), 
       'iyyyiw') AS "date",
   SUM(dollars) AS dollars
FROM my_table
GROUP BY 1
ORDER BY 1

让我解释一下。 DATE_PART将从您的日期列中提取星期数(日期从2016-10-032016-10-09的值为40,日期从2016-10-10到{{1 }}的值为2016-10-16,依此类推。)将其强制转换为41然后除以INTEGER将强制执行整数除法,并截断值({2将保留为2020将截断为{ {1}}等。保留这个截断的数字没有用,因此我将其乘以2以返回要分组的星期数。

我再次使用20.5从您的20列中检索年份,然后使用DATE_PART函数将年份和星期数连接起来,最后使用{{1 }}函数将包含年和周编号的字符串转换为日期格式(使用ISO标准)。

使用此新列将根据需要对数据进行分组。

尽管如此,仅由于您的数据从特定日期date开始,该日期具有一周的CONCAT,因此上述解决方案将按预期运行。让我研究另一个可以更好地推广其他日期范围的解决方案。

让我们假设您不希望根据从TO_DATE开始的两周分组,而希望按照2016-10-03开始的两周分组(前一周)。您可以使用与上述相同的解决方案,但必须稍加修改。

40

在提取星期时使用函数2016-10-03之后立即添加2016-09-26,会将所有星期“移动”到下一个“ bin”(星期SELECT TO_DATE( CONCAT( DATE_PART('YEAR', date), ((DATE_PART('WEEK', date) + 1)::INTEGER / 2) * 2 - 1), 'iyyyiw') AS "date", SUM(dollars) AS dollars FROM my_table GROUP BY 1 ORDER BY 1 移至{{1 }},第+1周移至DATE_PART等。当然,然后您必须拿走40才能返回到“原始”容器。但是,这将导致41除法开始以不同的方式截断所有内容,并且您的查询现在开始按41开始的两周分组数据。

回答您的问题

  

或者如果我想使用其他自定义日期范围怎么办?

上述解决方案可以很好地推广到其他情况,例如按三周,两个月分组等。

要开始按其他单位(天,周,月等)进行分组,只需将42函数更改为+1,然后将参数2更改为{{1 }}(在documentation中进行了描述)。您可以使用相同的技巧,使用2016-09-26DATE_PART('WEEK',...)从1月或2月开始对两个月进行分组。

例如,如果您希望按三周分组,则必须将数字除以DATE_PART('MONTH',...)乘以iyyyiw。在这里,如果您希望更改分组的前三周时间,则需要使用相同的技巧来添加iyyyim+1,但是现在可能需要使用{{1} }和-1

答案 1 :(得分:1)

如果您可以显示“每两周一次的期间号”,而不是显示该期间的开始日期,则可以执行以下操作:

SELECT
    FLOOR(EXTRACT(WEEK FROM dt) / 2) AS period,
    SUM(dollars) AS dollars
FROM t
GROUP BY FLOOR(EXTRACT(WEEK FROM dt) / 2)
ORDER BY FLOOR(EXTRACT(WEEK FROM dt) / 2)

哪个会给您这些结果:

period  dollars
20      3
21      4

在这种情况下,“期间”只是该期间的起始周的ISO周数除以2。您可以对其他范围执行类似的操作。这种方法的问题在于它与日期无关,而与ISO周号有关。