AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 292700
Accepted
Rahul
Rahul
Asked: 2021-06-04 01:28:42 +0800 CST2021-06-04 01:28:42 +0800 CST 2021-06-04 01:28:42 +0800 CST

Postgresql根据日期将单行拆分为多行[重复]

  • 772
这个问题在这里已经有了答案:
PostgreSQL:为表中的每个组生成一系列日期 2 个答案
去年关闭。

在我的例子中,我们有一个表 ABC,其中应该有 1 行。

ID 姓名 开始日期 结束日期
1 拉胡尔 2021 年 1 月 1 日 2021 年 6 月 1 日

但是在检索时,我想获得多行,其中开始日期递增 1,直到它小于或等于结束日期。

ID 姓名 开始日期 结束日期
1 拉胡尔 2021 年 1 月 1 日 2021 年 6 月 1 日
1 拉胡尔 2021 年 2 月 1 日 2021 年 6 月 1 日
1 拉胡尔 2021 年 3 月 1 日 2021 年 6 月 1 日
1 拉胡尔 2021 年 4 月 1 日 2021 年 6 月 1 日
1 拉胡尔 2021 年 5 月 1 日 2021 年 6 月 1 日
1 拉胡尔 2021 年 6 月 1 日 2021 年 6 月 1 日

请让我知道我们该怎么做。

database-design postgresql
  • 2 2 个回答
  • 1457 Views

2 个回答

  • Voted
  1. Best Answer
    Vérace
    2021-06-05T01:41:08+08:002021-06-05T01:41:08+08:00

    你可以通过几种方式来做到这一点(下面的所有代码都可以在 fiddle here上找到)。

    使用 GENERATE_SERIES 的解决方案:

    对于初学者,我插入了更多记录以使用例更加真实,我还在表中添加了一些合理的约束。

    CREATE TABLE test
    (
      id SMALLINT NOT NULL PRIMARY KEY,  -- PK added
      name TEXT NOT NULL,
      start_date DATE NOT NULL,
      end_date DATE NOT NULL,
      
      CONSTRAINT test_name_uq UNIQUE (name),   -- maybe, maybe not?
      CONSTRAINT sd_lt_ed_ck CHECK (start_date < end_date) -- important!
    );
    

    填充它:

    INSERT INTO test
    VALUES
    (1, 'Rahul', '2021-06-01', '2021-06-06'),
    (2, 'Bill' , '2021-06-02', '2021-06-10'),
    (3, 'Mary' , '2021-07-15', '2021-07-22'),
    (4, 'Fred' , '2021-07-20', '2021-07-27'),
    (5, 'Joe'  , '2021-08-01', '2021-08-04'),
    (6, 'Jim ' , '2021-09-04', '2021-09-05'),
    (7, 'John' , '2021-09-17', '2021-09-21');
    

    然后我运行了以下查询:

    SELECT 
      id, 
      GENERATE_SERIES 
        (t.start_date, t.end_date, '1 DAY')::DATE AS sd, 
      t.end_date
    FROM test t
    ORDER BY t.id, t.start_date;
    

    结果(为简洁起见 - 见小提琴):

    id  sd  end_date
    1   2021-06-01  2021-06-06
    1   2021-06-02  2021-06-06
    1   2021-06-03  2021-06-06
    1   2021-06-04  2021-06-06
    1   2021-06-05  2021-06-06
    1   2021-06-06  2021-06-06
    2   2021-06-02  2021-06-10
    2   2021-06-03  2021-06-10
    ...
    ...  more records
    ...
    

    仅连续两天的“边缘案例”也很有效:

    6   2021-09-04  2021-09-05
    6   2021-09-05  2021-09-05
    

    我对我的解决方案与@Akina 提供的另一个解决方案进行了性能分析,虽然我的解决方案似乎有更多的操作,但它始终比他的更快(通常约 2/3 的时间 - 虽然偶尔,我的速度较慢) . 看这里的小提琴。

    现在,当我们只查看我们无法控制的服务器上的 7 条记录时,不可能正确地对解决方案进行基准测试 - 机器上的其他地方发生了什么?我会敦促您使用您自己的(测试)系统测试任何选择的解决方案,以澄清这一点,让您自己满意。

    使用递归 CTE (RCTE) 的解决方案:

    另一个有趣的解决方案也存在使用RCTE如下:

    WITH RECURSIVE cte (n, id, sd, ed) AS
    (
      SELECT 1, t.id, t.start_date, t.end_date
      FROM test t
      UNION ALL
      SELECT n+1, c.id, (c.sd + INTERVAL '1 DAY')::DATE, c.ed
      FROM cte c
      WHERE c.sd < (SELECT z.end_date FROM test z WHERE z.id = c.id)
    )
    SELECT * FROM cte c2
    ORDER BY c2.id, c2.sd, c2.ed;
    

    结果:

    Same as for the query above - including the two consecutive days
    

    性能分析:

    我在fiddleEXPLAIN (ANALYZE, BUFFERS)中包含了两个查询的输出。如您所见,GENERATE_SERIES 查询占用了 RCTE 大约 50% 的时间。那么,您可能会问,为什么有人会为 RCTE 烦恼呢?

    好吧,它们非常强大,它们允许程序员向他们的查询添加复杂的逻辑——我敦促你去探索它们——也许不适合这种情况,但对于未来的场景来说,它们值得牢记。

    ps 欢迎来到 dba.se。为了将来参考,请不要在此处和StackOverflow上发布相同的问题。

    数据库问题在这里非常重要。如果您提出了问题并且在合理的时间内没有收到回复,请随时在其他地方提问,但是,在这种情况下,请将旧问题的链接添加到新问题以避免重复工作!

    • 1
  2. Akina
    2021-06-04T04:01:41+08:002021-06-04T04:01:41+08:00
    SELECT test.id, test.name, series.start_date::DATE, test.end_date
    FROM test
    CROSS JOIN generate_series(test.start_date, test.end_date, '1 day') AS series (start_date)
    

    https://dbfiddle.uk/?rdbms=postgres_12&fiddle=1f64e23f35bc9539cff6f9c93a2290cb

    • 0

相关问题

  • 运行时间偏移延迟复制的最佳实践

  • 存储过程可以防止 SQL 注入吗?

  • 在数据仓库中实现多对多关系有哪些方法?

  • PostgreSQL 中 UniProt 的生物序列

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve