【问题标题】:Running total of "matches" using a window function in SQL在 SQL 中使用窗口函数运行“匹配”总数
【发布时间】:2012-02-20 21:30:18
【问题描述】:

我想创建一个窗口函数,该函数将计算当前行中字段的值出现在当前行之前的有序分区部分中出现的次数。为了更具体,假设我们有一个这样的表:

| id| fruit  | date |
+---+--------+------+
| 1 | apple  |   1  |
| 1 | cherry |   2  |
| 1 | apple  |   3  |
| 1 | cherry |   4  |
| 2 | orange |   1  |
| 2 | grape  |   2  |
| 2 | grape  |   3  |

我们想创建一个像这样的表(为了清楚起见,省略了日期列):

| id| fruit  | prior |  
+---+--------+-------+
| 1 | apple  |   0   |
| 1 | cherry |   0   |
| 1 | apple  |   1   |
| 1 | cherry |   1   |
| 2 | orange |   0   |
| 2 | grape  |   0   |
| 2 | grape  |   1   |

请注意,对于id = 1,沿着有序分区移动,第一个条目“苹果”不匹配任何内容(因为隐含集合为空),下一个水果“樱桃”也不匹配。然后我们再次进入“apple”,这是一个匹配项,依此类推。我想象 SQL 看起来像这样:

SELECT
id, fruit, 
<some kind of INTERSECT?> OVER (PARTITION BY id ORDER by date) AS prior
FROM fruit_table; 

但我找不到任何看起来正确的东西。 FWIW,我使用的是 PostgreSQL 8.4。

【问题讨论】:

  • “日期”是否保证是连续的? (顺便说一句,“date”是保留字。“prior”在某些SQL实现中也是保留字)

标签: sql postgresql aggregate-functions window-functions


【解决方案1】:

您可以在没有窗口函数的情况下使用 self-left joincount() 来优雅地解决这个问题:

SELECT t.id, t.fruit, t.day, count(t0.*) AS prior
FROM   tbl t
LEFT   JOIN tbl t0 ON (t0.id, t0.fruit) = (t.id, t.fruit) AND t0.day < t.day
GROUP  BY t.id, t.day, t.fruit
ORDER  BY t.id, t.day

如果您的目的是使用 窗口函数,这个应该可以工作:

SELECT id, fruit, day
      ,count(*) OVER (PARTITION BY id, fruit ORDER BY day) - 1 AS prior
FROM   tbl
ORDER  BY id, day

如果省略 frame_end,则默认为当前行。

  • 您可以有效地计算前几天有多少行具有相同的(id, fruit) - 包括当前行。这就是 - 1 的用途。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 2021-08-22
    • 2012-11-22
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多