sql - Postgres 9.x 加入重叠的日期和时间范围

标签 sql postgresql postgresql-9.1 postgresql-9.2

我有几个表具有 TIMESTAMP WITH TIME ZONE 列以及一些附加信息。我需要能够加入这些表,以便每一行的所有信息在给定的日期和时间窗口(标记为 beginend 时都是“有效的”所需的结果集)。

我目前的做法:

选项#1

  1. 创建一个唯一的时间列表。
  2. 将每个时间点转换为唯一列表(“有效”时间窗口)和每个原始表的时间窗口。 [LEAD(...) OVER (...)]
  3. 将原始表连接到唯一的时间列表。

选项#2

  1. 将每个时间点 (TIMESTAMP WITH TIME ZONE) 转换为每个表的时间窗口。 [LEAD(...) OVER (...)]
  2. 加入窗口重叠的表格。
  3. 从每个窗口返回 GREATEST(foo.start, bar.start) & LEAST(foo.stop, bar.stop) 以找到真正的“有效”窗口。

例如:

表:foo

  fooid  |  description  |       datetime
---------|---------------|-----------------------
    1    |   Varsion 1   |  2010-01-01 00:00:00  
    2    |   Varsion 2   |  2010-07-01 00:00:00 

表格:条形图

  barid  |  fooid  |  description  |       datetime
---------|---------|---------------|-----------------------
    1    |    1    |   Varsion A   |  2010-01-01 00:00:00
    2    |    1    |   Varsion B   |  2010-02-01 00:00:00
    3    |    1    |   Varsion C   |  2010-03-01 00:00:00
    4    |    1    |   Varsion D   |  2010-04-01 00:00:00
    5    |    1    |   Varsion E   |  2010-05-01 00:00:00
    6    |    1    |   Varsion F   |  2010-06-01 00:00:00
    7    |    2    |   Varsion A   |  2010-07-01 00:00:00
    8    |    2    |   Varsion B   |  2010-08-01 00:00:00
    9    |    2    |   Varsion C   |  2010-09-01 00:00:00
    10   |    2    |   Varsion D   |  2010-10-01 00:00:00
    11   |    2    |   Varsion E   |  2010-11-01 00:00:00
    12   |    2    |   Varsion F   |  2010-12-01 00:00:00

简化的期望结果

        begin          |          end          |  fooid  |   foo_desc    |       foostart        |        foostop        |  barid  |   bar_desc   |       foostart        |        foostop        
-----------------------|-----------------------|---------|---------------|-----------------------|-----------------------|---------|--------------|-----------------------|-----------------------
         ...           |         ...           |   ...   |      ...      |         ...           |         ...           |   ...   |     ...      |         ...           |         ...           
  2010-05-01 00:00:00  |  2010-06-01 00:00:00  |    1    |   Varsion 1   |  2010-01-01 00:00:00  |  2010-07-01 00:00:00  |    5    |  Varsion E   |  2010-05-01 00:00:00  |  2010-06-01 00:00:00
  2010-06-01 00:00:00  |  2010-07-01 00:00:00  |    1    |   Varsion 1   |  2010-01-01 00:00:00  |  2010-07-01 00:00:00  |    6    |  Varsion F   |  2010-06-01 00:00:00  |        infinity
  2010-07-01 00:00:00  |  2010-08-01 00:00:00  |    2    |   Varsion 2   |  2010-07-01 00:00:00  |       infinity        |    7    |  Varsion A   |  2010-07-01 00:00:00  |  2010-08-01 00:00:00
  2010-08-01 00:00:00  |  2010-09-01 00:00:00  |    2    |   Varsion 2   |  2010-07-01 00:00:00  |       infinity        |    8    |  Varsion B   |  2010-08-01 00:00:00  |  2010-09-01 00:00:00
         ...           |         ...           |   ...   |      ...      |         ...           |         ...           |   ...   |     ...      |         ...           |         ...           

我的问题:

实现此目标的最佳方法是什么?我创建了一个 fiddle展示了两种不同的解决方案,我想听听关于每种解决方案的想法以及可能的解决方案。

更新#1:

在示例中,只有两个表需要连接……但是,在某些情况下,我可能需要连接多个表 3、4 或更多。

更新#2:

使用选项 #1,我的问题是当我有大结果集时,我发现初始子查询可能很大,而 postgres 不能使用索引。这会导致很大的性能损失。另一方面,我发现它是最准确的,因为我可以针对它LEFT OUTER JOIN 并获取相关的 NULL 数据。

使用选项 #2,查询计划器能够使用 TIMESTAMP WITH TIME ZONE 列上的索引;但是,在 FROM 子句中连接两个以上的表变得更加复杂。我可以将 (table1.start, table1.stop) OVERLAPS (table2.start, table2.stop) 移动到 WHERE 子句中,但随后我松开了相关的 数据。

所有这些让我想知道是否有更好的方法......

最佳答案

  • 为窗口函数使用默认值lead()和 lag() 而不是 coalesce()

lead(datetime, 1, 'infinity') OVER (ORDER BY fooid, datetime) AS stop

代替

COALESCE(LEAD(datetime) OVER (ORDER BY fooid, datetime), 'infinity'::TIMESTAMP) AS stop
  • 当您PARTITION BY fooid 时,ORDER BY fooid 毫无意义。

PARTITION BY fooid ORDER BY datetime

代替:

(PARTITION BY fooid ORDER BY fooid, datetime)
  • 您(或某些工具)将每个标识符都用双引号引起来,即使它们在没有引号的情况下都是合法的。使查询更难阅读。消除噪音。

除此之外:您的问题对 stackoverflow 来说太宽泛,而且描述很难理解。

考虑:https://codereview.stackexchange.com/

关于sql - Postgres 9.x 加入重叠的日期和时间范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17332751/

相关文章:

json - Postgresql,解析JSON

sql - 如何在postgres中创建具有按年求和的值的表

sql - 将行转置为单列

sql - 在 PSQL 中将字符串转换为十进制

postgresql - postgresql中的移动平均线

sql - 如何在 PostgreSQL 中将 NULL 值设置为数字?

c# - 检索 scope_identity 时指定的转换无效

sql - 从内部查询中查找不同的值

c# - InvalidCastException : Unable to cast object of type 'System.DBNull' to type 'System.Nullable` 1[System. Int32]'

javascript - 将 Node/Sequelize 应用程序部署到 heroku - PORT 问题