【问题标题】:How to get the last day of month in postgres?如何在postgres中获得一个月的最后一天?
【发布时间】:2015-03-26 23:37:59
【问题描述】:

如何在 postgres 中找到该月的最后一天? 我有一个日期列以格式(YYYYMMDD)存储为数字(18) 我正在尝试使用

to_date("act_dt",'YYYYMMDD') AS "act date"

然后找到该日期的最后一天: 像这样:

(select (date_trunc('MONTH',to_date("act_dt",'YYYYMMDD')) + INTERVAL '1 MONTH - 1 day')::date)

但它给了我这个错误:

ERROR: Interval values with month or year parts are not supported
  Detail: 
  -----------------------------------------------
  error:  Interval values with month or year parts are not supported
  code:      8001
  context:   interval months: "1"
  query:     673376
  location:  cg_constmanager.cpp:145
  process:   padbmaster [pid=20937]
  -----------------------------------------------

有什么帮助吗?

Postgres 版本:

PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.874

【问题讨论】:

  • to_date 仅将字符串转换为日期。如果您的列包含 Unix 纪元值,则需要使用 to_timestamp:to_timestamp(act_dt)::date
  • @AudriusKažukauskas:错误:函数 to_timestamp(numeric) 不存在提示:没有函数与给定名称和参数类型匹配。您可能需要添加显式类型转换。 ?
  • to_timestamp 需要双精度类型,尝试将您的列转换为它:to_timestamp(act_dt::float8)::date。顺便说一句,您能否确认此列存储 Unix 纪元时间值?如果不是这种情况,您应该在您的问题中解释它到底存储了什么。
  • 您可以通过将INTERVAL '1 MONTH - 1 day' 替换为INTERVAL '1 MONTH' - interval '1 day' 来进行计算
  • @AudriusKažukauskas :该列的值类似于 act_dt 20131014 20130614 20150124 20110128 20120825

标签: sql amazon-redshift


【解决方案1】:

对于任何来此问题寻找 Postgres 方法(不使用 Redshift)的人,您可以这样做:

SELECT (date_trunc('month', '2017-01-05'::date) + interval '1 month' - interval '1 day')::date
AS end_of_month;

'2017-01-05' 替换为您要使用的任何日期。你可以把它变成这样的函数:

create function end_of_month(date)
returns date as
$$
select (date_trunc('month', $1) + interval '1 month' - interval '1 day')::date;
$$ language 'sql'
immutable strict;

编辑 Postgres 11+

@Gabriel 的 cmets 中提取它,您现在可以将区间表达式合并到一个 interval 中(这会使事情变得更短一些):

select (date_trunc('month', now()) + interval '1 month - 1 day')::date as end_of_month;

-- +--------------+
-- | end_of_month |
-- +--------------+
-- | 2021-11-30   |
-- +--------------+
-- (1 row)

【讨论】:

  • last_day 更简单,也可能比您的解决方案更快。为什么有人应该使用所有这些东西而不是简单的 last_day ?
  • @giò 因为 last_day 是一个红移函数。正如我在回答中所说,这就是你如何只用 PostgreSQL 做同样的事情。对于那些提出这个问题并且没有使用 redshift 的人来说,这就是他们可以实现与 last_day 函数相同的事情的方法。至于是快还是慢,谁能说?随意自己测试它们,您可以通知我们所有人。
  • 哦,我不知道 postgres 没有 last_day 功能,真可惜
  • 你也可以在单个区间内做区间数学,至少在 PG11+ select date_trunc('month', now()) + interval '1 month -1 day'
【解决方案2】:

如果您使用的是 Amazon AWS Redshift,则可以使用 Redshift 的 LAST_DAY 函数。 Redshift 基于 PostgreSQL,LAST_DAY 函数在 PostgreSQL 中不可用,用于 PostgreSQL 的解决方案see @wspurgin's answer

https://docs.aws.amazon.com/redshift/latest/dg/r_LAST_DAY.html

LAST_DAY( { date | timestamp } )

LAST_DAY 返回包含日期的月份的最后一天的日期。无论日期参数的数据类型如何,返回类型始终为 DATE

例如:

SELECT LAST_DAY( TO_DATE( act_date, 'YYYYMMDD' ) )

【讨论】:

  • ERROR: Interval values with month or year parts are not supported Detail: ----------------------------------------------- error: Interval values with month or year parts are not supported code: 8001 context: interval months: "1" query: 674275 有什么帮助吗?
  • @HareRamaHareKrishna:您的确切 Postgres 版本是什么?请编辑您的问题并将select version() 的输出添加到您的问题中。
  • 并不真正了解redShift,但试试这个:select dateadd(day,-1,dateadd(month,1,date_trunc('month',to_date(to_char(act_dt,'99999999'), 'YYYYMMDD'))))
  • Here 他们在谈论last_day 功能,你可以试试:select last_day(to_date(to_char(act_dt,'999999‌​99'), 'YYYYMMDD')) 吗?
  • last_day() 不是 Postgres 函数。虽然它适用于原始海报(最后他们确实说他们在 AWS Redshift 上运行 PostgreSQL 8.0.2),但它实际上并不能回答他们提出的问题,特别是“如何在 postgres 中获取一个月的最后一天?”
【解决方案3】:
date_trunc('month',current_date) + interval '1 month' - interval '1 day'

将任何日期或时间戳截断到月份级别将为您提供包含该日期的月份的第一天。添加一个月会给您下个月的第一天。然后,删除一天将为您提供所提供日期当月的最后一天的日期。

【讨论】:

    【解决方案4】:

    select to_char(date_trunc('month', now() + '01 Months'::interval) - '01 Days'::interval, 'YYYYmmDD'::text)::numeric as end_period_n

    【讨论】:

      【解决方案5】:

      对于未来的搜索,Redshift 不接受INTERVAL '1 month'。而是使用dateadd(month, 1, date) 记录的here

      要在月底使用:DATEADD(DAY, -1, (DATE_TRUNC('month', DATEADD(MONTH, 1, date))))

      【讨论】:

        【解决方案6】:

        好的,所以你有一个 numeric(18) 列,其中包含像 20150118 这样的数字。您可以将其转换为如下日期:

        to_date(your_date_column::text, 'YYYYMMDD')
        

        从一个日期,你可以抓住the last day of the monthlike:

        (date_trunc('month', your_date_column) + 
            interval '1 month' - interval '1 day')::date;
        

        结合起来,你会得到:

        select  (date_trunc('month', to_date(act_dt::text, 'YYYYMMDD')) + 
                   interval '1 month' - interval '1 day')::date
        from    YourTable;
        

        Example at SQL Fiddle.

        【讨论】:

        • Andomar: Now() 是我的integer date,需要让它成为日期,然后用它代替 now().. 这样的东西不起作用(select (date_trunc('MONTH',to_date("act_dt",'YYYYMMDD')) + INTERVAL '1 MONTH - 1 day')::date) it gives me error as above
        • @HareRamaHareKrishna:从您的问题中可以明显看出,抱歉。更新了答案。
        • 错误:函数 to_timestamp(numeric) 不存在 提示:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换。 ?
        • 对我来说,它适用于数字参数...您使用的是哪个版本的 Postgres? to_timestamp(act_dt::float) 有效吗?其中::type 是 Postgres 类型转换。
        • hmm.. 我用它把它转换成日期to_date("act_dt",'YYYYMMDD')
        猜你喜欢
        • 2010-09-07
        • 2011-01-30
        • 1970-01-01
        • 2015-02-06
        • 1970-01-01
        • 2012-04-01
        • 1970-01-01
        相关资源
        最近更新 更多