查询滚动日期范围和国家/地区中不同值的计数

Query for count of distinct values in a rolling date range and country

亲爱的 Stack overflow 社区,晚上好。 这是我的第一个问题。

我遇到以下问题:我需要一个查询来计算每个国家/地区滚动日期范围(3 天)内的不同值。

我做了一些研究,发现了以下讨论[1]:Query for count of distinct values in a rolling date range

对于我面临的问题,我不仅需要按日期分组,还需要按国家/地区分组。请考虑以下输入 table:

Date Country Email
1/1/12 DE de1@example.com
1/1/12 FRA fra1@example.com
1/1/12 SPA spa1@example.com
1/2/12 DE de1@example.com
1/2/12 DE de2@example.com
1/3/12 SPA spa1@example.com
1/3/12 SPA spa2@example.com
1/3/12 FRA fra2@example.com
1/4/12 SPA spa1@example.com
1/4/12 FRA fra2@example.com
1/4/12 FRA fra3@example.com
1/4/12 SPA spa3@example.com

计算不同电子邮件的预期结果如下:

Date Country Email
1/1/12 DE 1
1/1/12 FRA 1
1/1/12 SPA 1
1/2/12 DE 2
1/2/12 FRA 1
1/2/12 SPA 1
1/3/12 SPA 2
1/3/12 DE 2
1/3/12 FRA 2
1/4/12 SPA 3
1/4/12 FRA 2
1/4/12 DE 2

我试图修改上述讨论中建议的解决方案,并通过在选定列和分组中添加国家/地区来修改以下内容。

SELECT date
     ,(SELECT count(DISTINCT email)
       FROM   tbl
       WHERE  date BETWEEN g.date - 2 AND g.date
      ) AS dist_emails
FROM  (SELECT generate_series(timestamp '2012-01-01'
                            , timestamp '2012-01-06'
                            , interval  '1 day')::date) AS g(date)

不幸的是,更新后的查询不起作用,因为无法识别国家并且会出错。

SELECT date, country,
         ,(SELECT count(DISTINCT email)
           FROM   tbl
           WHERE  date BETWEEN g.date - 2 AND g.date
          ) AS dist_emails
    FROM  (SELECT generate_series(timestamp '2012-01-01'
                                , timestamp '2012-01-06'
                                , interval  '1 day')::date) AS g(date)
GROUP BY 1,2

非常感谢您的建议并分享您在解决此问题方面的专业知识。

country 不存在的原因是我们只能从查询的 FROM 部分中的 table 中获取 SELECT 列。嵌套子查询 selects from tbl 但主外部查询不可用,它仅来自生成的 table g selects。 g 只有一个 date 列,因此这是外部查询可以直接 select 的唯一列。

查询的另一个问题是 COUNT 没有考虑国家。

为此,我将使用基本连接来查询每个日期范围的每一行,然后对每个日期 + 国家/地区执行 count distinct。您可以使用 INNER 联接删除没有条目的日期,或者如果该日期范围没有条目,则可以删除 LEFT OUTER{date}, nil,nil 的 return 行。类似于:

SELECT g.date
     , tbl.country
     , COUNT(DISTINCT(tbl.email))
    FROM  (SELECT generate_series(timestamp '2012-01-01'
                                , timestamp '2012-01-06'
                                , interval  '1 day')::date) AS g(date)
    INNER JOIN tbl ON (tbl.date BETWEEN g.date - 2 AND g.date)

GROUP BY 1,2