我有一个案例,我想提取DID
在特定时间段内每天存在一次且仅存在一次的设备 ID ( )。我尝试了不同的方法和分区,但我似乎只能每天单独获取该数据(where date = X
),但我需要使用where date between X and Y
.
示例数据:
DID date
A 2019-01-01
A 2019-01-01
A 2019-01-02
A 2019-01-03
B 2019-01-01
B 2019-01-02
B 2019-01-03
C 2019-01-01
C 2019-01-02
C 2019-01-02
C 2019-01-03
D 2019-01-01
D 2019-01-02
D 2019-01-03
查询应该只返回B & D因为从 01 到 03 每天存在一次。
我还希望得到count,在这种情况下为2
如果每个日期至少有一个,但有多个日期,则 count(date) 将 > 3。如果某个日期少于一个,则 count(distinct date) 将 < 3。
弄清楚 B 和 D 的基数为 2 似乎很容易。这真的需要在查询中完成吗?如果是这样,请使用窗口函数
测试表:
测试数据:
很容易做到
did
每天只发生一次:结果:
这是它变得更加复杂的地方。这完全取决于你想如何传递日期......
我假设您想从表中的完整数据集中获取日期范围。如果您不这样做,您可以修改 CTE 以提供开始和结束日期。
我将从答案的扩展版本开始,以演示它是如何工作的。
我们计算日期的差异以获得所涉及的天数,然后检查
did
s 的计数以查看它们是否每天都出现。瘦身版:
如果您想知道这些东西是什么,请在此处
with .... as (
阅读公用表表达式。小提琴链接在这里。
这是关系除法的特例。谓词日期恰好是按顺序排列的,重复的被排除在外。有许多可能的解决方案。最佳匹配取决于完整的用例。
例如,如果
did
您需要优化性能并且您的表很大并且该列具有高基数并且通常只有少数did
符合条件并且在 上有一个索引(dt, did)
,那么这个查询应该比使用&的查询快得多:GROUP BY
count()
为什么?因为它可以通过一些相对非常便宜的索引(仅)扫描来回答您的查询,并尽早排除不合格的行,而基于查询的查询
GROUP BY
始终必须处理整个表。ctid
在我的示例中,可以安全地回退以识别各个列,而我们不知道您的实际设计。对于长日期范围,这会变得冗长。动态生成查询可能是值得的。或者混合的方法可能是有意义的。或者使用递归 CTE使其简短且仍然非常快:
此变体返回一组合格的 ID 和一个计数。
db<>在这里摆弄
相关:(推荐阅读!)
这一切都取决于实际的完整用例。
还有相关的: