【问题标题】:Query with CASE and generate_series(), order resulting timestamptz descending使用 CASE 和 generate_series() 查询,结果 timestamptz 降序排列
【发布时间】:2017-08-21 06:48:26
【问题描述】:

我是新手,正在尝试使用以下代码创建一个函数:

CREATE OR REPLACE FUNCTION public.get_bulan()
returns table (request_detail timestamp with time zone)
language plpgsql stable
as $function$
        begin
        return query

        select
        case
        when (extract(DAY FROM now()) >= 25) then generate_series(date_trunc('year', now()), date_trunc('day', now()) ,interval '1 month')
        when (select extract(month FROM now()) = 2) then now() - (interval '1' month * generate_series(0,1))
        when (select extract(month FROM now()) = 1) then now() - (interval '1' month * generate_series(0,2))
        else generate_series((select date(date_trunc('year', now()))), (select date(now())-'1 month'::interval), interval '1 month')
        end
        order by timetstamptz(request_detail) desc;
        end;
        $function$;

上面查询的结果是:

2017-01-01 00:00:00
2017-02-01 00:00:00
2017-03-01 00:00:00
2017-04-01 00:00:00
2017-05-01 00:00:00
2017-06-01 00:00:00
2017-07-01 00:00:00

我尝试使用order by descorder by timestamp desc,但它不起作用。我想按降序排列,所以我得到了从 2017-07-01 到 2017-01-01 的结果。我该怎么做?

【问题讨论】:

  • 好兄弟,你要程序还是明确查询?
  • 程序呢?
  • 你得到的结果有什么问题?对我来说看起来排序正确。
  • request_detail 会在结果中丢失,因此需要为 @a_horse_with_no_name 添加一个名称
  • 是的,谢谢先生 :)

标签: sql postgresql sql-order-by plpgsql set-returning-functions


【解决方案1】:

您有两种方法可以做到这一点:

  1. 添加as result_timestamp order by result_timestamp desc;

    CREATE OR REPLACE FUNCTION public.get_bulan()
     returns table (request_detail timestamp with time zone)
     language plpgsql stable
     as $function$
        begin
        return query
    
        select 
        case
        when (extract(DAY FROM now()) >= 25) then generate_series(date_trunc('year', now()), date_trunc('day', now()) ,interval '1 month')
        when (select extract(month FROM now()) = 2) then now() - (interval '1' month * generate_series(0,1))
        when (select extract(month FROM now()) = 1) then now() - (interval '1' month * generate_series(0,2))
        else generate_series((select date(date_trunc('year', now()))), (select date(now())-'1 month'::interval), interval '1 month')
        end as result_timestamp order by result_timestamp desc;
    
        end;
        $function$;
    
  2. 或者,当您从其他地方调用它时,您可以从过程中删除排序和订单:

    CREATE OR REPLACE FUNCTION public.get_bulan()
    returns table (request_detail timestamp with time zone)
    language plpgsql stable
    as $function$
            begin
            return query
    
            select 
            case
            when (extract(DAY FROM now()) >= 25) then generate_series(date_trunc('year', now()), date_trunc('day', now()) ,interval '1 month')
            when (select extract(month FROM now()) = 2) then now() - (interval '1' month * generate_series(0,1))
            when (select extract(month FROM now()) = 1) then now() - (interval '1' month * generate_series(0,2))
            else generate_series((select date(date_trunc('year', now()))), (select date(now())-'1 month'::interval), interval '1 month')
            end;
    
            end;
            $function$;
    

并调用:

select request_detail from public.get_bulan() order by request_detail desc

注意:第二个非常柔韧,您可以轻松操作。

【讨论】:

  • 这缺少核心问题:CASE 分支中的排序顺序相矛盾。还有更多的问题。我添加了一个答案。
  • 老兄,这是另类的
  • 好的,看起来是出于善意和主题。我删除了反对票。它只是没有解决问题。
【解决方案2】:
 select
        (case 
        when (extract(DAY FROM now()) >= 25) then generate_series(date_trunc('year', now()), date_trunc('day', now()) ,interval '1 month')
        when (select extract(month FROM now()) = 2) then now() - (interval '1' month * generate_series(0,1))
        when (select extract(month FROM now()) = 1) then now() - (interval '1' month * generate_series(0,2))
        else generate_series((select date(date_trunc('year', now()))), (select date(now())-'1 month'::interval), interval '1 month')
        end) as time_st  order by time_st desc

输出:

2017-07-01 00:00:00+05:30
2017-06-01 00:00:00+05:30
2017-05-01 00:00:00+05:30
2017-04-01 00:00:00+05:30
2017-03-01 00:00:00+05:30
2017-02-01 00:00:00+05:30
2017-01-01 00:00:00+05:30

【讨论】:

    【解决方案3】:

    SQL CASE 语句的第一个和最后一个分支按降序返回行,其他两个按升序返回。因此,您需要在外部 SELECT 中添加另一个 ORDER BY

    干净的解决方法是让所有 4 个分支以相同的顺序返回行。

    或者更确切地说,完全重写它以解开混乱:

    SELECT *
    FROM   generate_series(
             CASE
                WHEN extract(DAY   FROM now()) >= 25 THEN date_trunc('month', now())
                WHEN extract(MONTH FROM now()) <=  2 THEN now()
                ELSE                                      now() - interval '1 month'
             END
           , date_trunc('year' , now())
           , interval '- 1 month'  -- negative interval
          ) t(request_detail)
    ORDER  BY request_detail DESC;  -- redundant
    

    负区间自动产生降序。可以加ORDER BY request_detail DESC,让标准SQL清晰无误。

    如果你愿意,可以将查询包装成一个函数。

    最重要的是,不要CASE 语句中包装像generate_series() 这样的集合返回函数。这从来都不是一个好主意,但从 Postgres 10 开始,它会引发错误:

    ERROR:  set-returning functions are not allowed in CASE
    

    演示:

    dbfiddle here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多