我有几个表具有 TIMESTAMP WITH TIME ZONE
列以及一些附加信息。我需要能够加入这些表,以便每一行的所有信息在给定的日期和时间窗口(标记为 begin
和 end
时都是“有效的”所需的结果集)。
我目前的做法:
选项#1
- 创建一个唯一的时间列表。
- 将每个时间点转换为唯一列表(“有效”时间窗口)和每个原始表的时间窗口。 [
LEAD(...) OVER (...)
] - 将原始表连接到唯一的时间列表。
选项#2
- 将每个时间点 (
TIMESTAMP WITH TIME ZONE
) 转换为每个表的时间窗口。 [LEAD(...) OVER (...)
] - 加入窗口重叠的表格。
- 从每个窗口返回
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 来说太宽泛,而且描述很难理解。
关于sql - Postgres 9.x 加入重叠的日期和时间范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17332751/