【问题标题】:How to transform this data in PostgreSQL如何在 PostgreSQL 中转换这些数据
【发布时间】:2021-04-12 19:56:40
【问题描述】:

如何转换这些数据

Date1 Date2 ID
2021-01-01 2021-01-04 1
2021-01-05 2021-01-25 2

进入这个

Date ID
2021-01-01 1
2021-01-02 1
2021-01-03 1
2021-01-04 1
2021-01-05 2
2021-01-06 2
... ...
2021-01-24 2
2021-01-25 2

我正在使用 Postgres,直觉告诉我在 Postgres 中使用 generate_series 函数,但我不确定实现。任何帮助表示赞赏。

【问题讨论】:

    标签: sql postgresql date common-table-expression


    【解决方案1】:

    你的直觉是正确的,日历表方法应该在这里工作:

    WITH dates AS (
        SELECT date_trunc('day', dt)::date AS dt
        FROM generate_series (
            '2021-01-01'::timestamp,
            '2021-01-31'::timestamp,
            '1 day'::interval) dt
    )
    
    SELECT d.dt AS Date, t.ID
    FROM dates d
    LEFT JOIN yourTable t
        ON d.dt BETWEEN t.Date1 AND t.Date2;
    

    Demo

    【讨论】:

      【解决方案2】:

      因为我们可能无法提前知道开始日期和结束日期的界限。

      这是一种方法

      WITH yourTable AS (
          SELECT '2021-01-01'::date AS Date1, '2021-01-04'::date AS Date2, 1 AS ID 
          UNION ALL
          SELECT '2021-01-05'::date, '2021-01-25'::date, 2
      )
      select x.date1 + (lvl-1)*INTERVAL '1 day'
             ,x.id
        from yourTable x
        join generate_series(1,date2-date1+1) as lvl
          on 1=1
      
      db fiddle
      https://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=3ef42eb613422c148b76561522d33a55
      
      
      +---------------------+----+
      |        date1        | id |
      +---------------------+----+
      | 2021-01-01 00:00:00 |  1 |
      | 2021-01-02 00:00:00 |  1 |
      | 2021-01-03 00:00:00 |  1 |
      | 2021-01-04 00:00:00 |  1 |
      | 2021-01-05 00:00:00 |  2 |
      | 2021-01-06 00:00:00 |  2 |
      | 2021-01-07 00:00:00 |  2 |
      | 2021-01-08 00:00:00 |  2 |
      | 2021-01-09 00:00:00 |  2 |
      | 2021-01-10 00:00:00 |  2 |
      | 2021-01-11 00:00:00 |  2 |
      | 2021-01-12 00:00:00 |  2 |
      | 2021-01-13 00:00:00 |  2 |
      | 2021-01-14 00:00:00 |  2 |
      | 2021-01-15 00:00:00 |  2 |
      | 2021-01-16 00:00:00 |  2 |
      | 2021-01-17 00:00:00 |  2 |
      | 2021-01-18 00:00:00 |  2 |
      | 2021-01-19 00:00:00 |  2 |
      | 2021-01-20 00:00:00 |  2 |
      | 2021-01-21 00:00:00 |  2 |
      | 2021-01-22 00:00:00 |  2 |
      | 2021-01-23 00:00:00 |  2 |
      | 2021-01-24 00:00:00 |  2 |
      | 2021-01-25 00:00:00 |  2 |
      +---------------------+----+
      

      【讨论】:

        【解决方案3】:

        我强烈建议使用横向连接和generate_series()

        select gs.date, t.id
        from t cross join lateral
             generate_series(t.date1, t.date2, interval '1 day') gs(date);
        

        Here 是一个 dbfiddle。

        为什么我推荐这个而不是left join?基本上,generate_series() 一次在一行上运行。所以,执行计划基本上应该是“读取一行,生成对应的行”。

        使用left join,Postgres 必须实际匹配所有行中的数据,而且该操作的成本要高得多。

        【讨论】:

          猜你喜欢
          • 2021-12-25
          • 1970-01-01
          • 1970-01-01
          • 2022-12-23
          • 2016-06-22
          • 2019-08-17
          • 2021-05-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多