按窗口功能计数

时间:2014-10-09 08:12:03

标签: sql postgresql window-functions

我创建了这个sqlfiddle来执行此查询:

SELECT "emails".*
FROM (
    SELECT "emails".id, sender_contact_id, sender_user_id,
    rank() OVER (PARTITION BY "sender_contact_id" ORDER BY "sent_at" DESC) AS "contact_rnk",
    rank() OVER (PARTITION BY "sender_user_id" ORDER BY "sent_at" DESC) AS "user_rnk"
    FROM "emails"
    WHERE ("folder" = 'INBOX')
) AS "e"
INNER JOIN "emails"
ON ("emails"."id" = "e"."id")
WHERE ((contact_rnk = 1 or user_rnk = 1) AND folder = 'INBOX')
ORDER BY sent_at DESC;

查询的目的是为每个发送电子邮件的联系人或用户仅返回1行。

查询中缺少的是为每个分区用户或联系人发送的电子邮件数。

我可以使用查询做多个并最后加入,例如

with main as (
  select blbah, etc.
),
cnt_users as (
  select count(sender_user_id) inner join main etc.
),
cnt_contacts as (
  select count(sender_contact_id) inner join main etc.
)
select main.*, cntusers etc.

但是,是否可以在第一个查询中包含计数而无需使用group by

1 个答案:

答案 0 :(得分:0)

行可以在没有GROUP BY的每个分区内计算,诀窍是使用正确的框架。

例如,查询可以修改为:

SELECT "emails".*, e.*
FROM (
    SELECT "emails".id, sender_contact_id, sender_user_id,
    rank() OVER (w1) AS "contact_rnk",
    count(*) OVER (w1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS contact_count,
    rank() OVER (w2) AS "user_rnk",
    count(*) OVER (w2 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS user_count
    FROM "emails"
    INNER JOIN email_participants ep
    ON emails.id = ep.email_id
    WHERE (folder = 'INBOX') and user_id = 220
    WINDOW
    w1 as (PARTITION BY sender_contact_id ORDER BY sent_at DESC),
    w2 as (PARTITION BY sender_user_id ORDER BY sent_at DESC)
) AS e
INNER JOIN emails
ON (emails.id = e.id)
WHERE ((contact_rnk = 1 or user_rnk = 1) AND folder = 'INBOX')
ORDER BY sent_at DESC

然后e.contact_counte.user_count应分别包含每个不同sender_contact_idsender_user_id的邮件计数。