【发布时间】:2017-12-19 05:49:24
【问题描述】:
我正在尝试找出一种方法来删除具有重叠时间的记录,但我无法找到一种简单而优雅的方法来保留所有但一个重叠的记录。这个问题类似于this one,但有一些不同。我们的表格如下所示:
╔════╤═══════════════════════════════════════╤══════════════════════════════════════╤════════╤═════════╗
║ id │ start_time │ end_time │ bar │ baz ║
╠════╪═══════════════════════════════════════╪══════════════════════════════════════╪════════╪═════════╣
║ 0 │ Mon, 18 Dec 2017 16:08:33 UTC +00:00 │ Mon, 18 Dec 2017 17:08:33 UTC +00:00 │ "ham" │ "eggs" ║
╟────┼───────────────────────────────────────┼──────────────────────────────────────┼────────┼─────────╢
║ 1 │ Mon, 18 Dec 2017 16:08:32 UTC +00:00 │ Mon, 18 Dec 2017 17:08:32 UTC +00:00 │ "ham" │ "eggs" ║
╟────┼───────────────────────────────────────┼──────────────────────────────────────┼────────┼─────────╢
║ 2 │ Mon, 18 Dec 2017 16:08:31 UTC +00:00 │ Mon, 18 Dec 2017 17:08:31 UTC +00:00 │ "spam" │ "bacon" ║
╟────┼───────────────────────────────────────┼──────────────────────────────────────┼────────┼─────────╢
║ 3 │ Mon, 18 Dec 2017 16:08:30 UTC +00:00 │ Mon, 18 Dec 2017 17:08:30 UTC +00:00 │ "ham" │ "eggs" ║
╚════╧═══════════════════════════════════════╧══════════════════════════════════════╧════════╧═════════╝
在上面的示例中,所有记录都有重叠时间,其中 重叠 仅表示由记录的 start_time 和 end_time(包括)定义的时间范围覆盖或延伸到另一个记录的一部分记录。然而,对于这个问题,我们不仅对那些具有重叠时间的记录感兴趣,而且对匹配的 bar 和 baz 列(上面的第 0、1 和 3 行)感兴趣。找到这些记录后,我们想删除除最早的以外的所有记录,只留下记录 2 和 3,因为记录 2 没有匹配的 bar 和 baz 列,而 3 有并且具有最早的开始和结束次。
这是我目前所拥有的:
delete from foos where id in (
select
foo_one.id
from
foos foo_one
where
user_id = 42
and exists (
select
1
from
foos foo_two
where
tsrange(foo_two.start_time::timestamp, foo_two.end_time::timestamp, '[]') &&
tsrange(foo_one.start_time::timestamp, foo_one.end_time::timestamp, '[]')
and
foo_one.bar = foo_two.bar
and
foo_one.baz = foo_two.baz
and
user_id = 42
and
foo_one.id != foo_two.id
)
);
感谢阅读!
更新:我找到了一个适合我的解决方案,基本上我可以将窗口函数 row_number() 应用到由 bar 和 baz 字段分组的表分区上,然后添加 @987654336 @ 子句添加到 DELETE 语句,排除第一个条目(具有最小 id 的条目)。
delete from foos where id in (
select id from (
select
foo_one.id,
row_number() over(partition by
bar,
baz
order by id asc)
from
foos foo_one
where
user_id = 42
and exists (
select
*
from
foos foo_two
where
tsrange(foo_two.start_time::timestamp,
foo_two.end_time::timestamp,
'[]') &&
tsrange(foo_one.start_time::timestamp,
foo_one.end_time::timestamp,
'[]')
and
foo_one.id != foo_two.id
)
) foos where row_number <> 1
);
【问题讨论】:
-
请编辑您的问题并添加一些sample data 和基于该数据的预期输出。 Formatted text 请no screen shots.
-
我很好奇为什么这被标记为 ruby-on-rails
-
因为它是一个 RoR 项目,我不希望人们在上面的查询中被 ruby 样式的字符串插值绊倒。
-
我明白了。但是,您已经用 foos 掩盖了其他所有内容。那么为什么不也屏蔽字符串插值,把它变成一个非常纯粹的 postgreSQL 问题呢?
标签: sql postgresql optimization