PostgreSQL - 获取统计数据

时间:2012-02-07 12:23:07

标签: sql postgresql select

我需要在我的应用程序中收集一些统计信息。 我有一个用户表(tb_user) 每次新用户访问应用程序时,它都会在此表中添加一条新记录,即每个用户一行。主要字段是 id date_hour (第一次用户访问应用程序时的时间戳)。

tb_user

id (bigint) | date_time (timestamp with time zone)
 1          |  2012-01-29 11:29:50.359-03
 2          |  2012-01-31 14:27:10.359-03

我需要得到:

以天,周和月为单位的平均用户数量

示例:

白天:55.45

按周:XX.XX

月:XX.XX

修改

我最好的解决方案是:

WITH daily_count AS (SELECT COUNT(id) AS user_count FROM tb_user)
SELECT user_count, tbaux2.days, (user_count/tbaux2.days) FROM daily_count, 
    (SELECT EXTRACT(DAY FROM (t2.diff) ) + 1 AS days
     FROM
       (with tbaux AS(SELECT  min(date_time) AS min FROM tb_user)
       SELECT (now() - min) AS diff
       FROM tbaux) AS t2) AS tbaux2
GROUP BY user_count, tbaux2.days

但是这个解决方案只适用于EXTRACT(DAY ......周和月都不起作用

欢迎任何帮助。

可替换地:

SELECT user_count, tbaux2.days, (user_count/tbaux2.days) AS userPerDay, ((user_count/tbaux2.days) * 7) AS userPerWeek, ((user_count/tbaux2.days) * 30) AS userPerMonth

编辑2:

基于@Bruno的回复,有一些注意事项:

当我问这个问题时,我确实要求按日,月和年选择数据。我相信我发布的搜索和@Bruno精炼,应该被解释为“每天,每7天和每30天”的平均值,而不是数天,数周和数月。我相信如果以这种方式解释,就不会出现性别引用的问题(10%下降)。我相信这种“每一个”的方法都是我需要的答案,所以会签署这个答案。

我建议改善帖子:

  • 仅考虑结果中的休息日(不收集当天的用户,不计算当前的分部日期)
  • 结果是两位数字。
  • 每周和每月都在考虑数据的新研究。

感谢。

1 个答案:

答案 0 :(得分:18)

你应该研究aggregate functions(min,max,count,avg),它与GROUP BY齐头并进。对于基于日期的聚合,date_trunc也很有用。

例如,这将返回每天的行数:

SELECT date_trunc('day', date_time) AS day_start,
       COUNT(id) AS user_count FROM tb_user
    GROUP BY date_trunc('day', date_time);

然后,您可以使用类似的内容(使用a CTE)执行每日平均值:

WITH daily_count AS (SELECT date_trunc('day', date_time) AS day_start,
       COUNT(id) AS user_count FROM tb_user
    GROUP BY date_trunc('day', date_time))
SELECT AVG(user_count) FROM daily_count;

使用'week'而不是每天计算每周计数,依此类推(请参阅date_trunc文档)。

编辑:(以下评论:平均至2012年5月1日,即6日之前。)

WITH daily_count AS (SELECT date_trunc('day', date_time) AS day_start,
       COUNT(id) AS user_count
    FROM tb_user
       WHERE date_time >= DATE('2012-01-01') AND date_time < DATE('2012-01-06') 
    GROUP BY date_trunc('day', date_time))
SELECT SUM(user_count)/(DATE('2012-01-06') - DATE('2012-01-01')) FROM daily_count;

在这种情况下,上面的内容过于复杂。这应该给你相同的结果:

SELECT COUNT(id)/(DATE('2012-01-06') - DATE('2012-01-01'))
    FROM tb_user
       WHERE date_time >= DATE('2012-01-01') AND date_time < DATE('2012-01-06');

编辑2:编辑完成后,我想您所追求的只是数据库整个存在期间的单一全球平均值,而不是按月/周/日分组。

这应该为您提供每天的平均行数:

WITH total_min_max AS (SELECT
        COUNT(id) AS total_visits,
        MIN(date_time) AS first_date_time,
        MAX(date_time) AS last_date_time,
    FROM tb_user)
SELECT total_visits/((last_date_time::date-first_date_time::date)+1) AS users_per_day
    FROM total_min_max

(我会将last_date_time替换为NOW()以达到目前为止的平均值,而不是直到最后一次访问,如果没有最近的访问。)

然后,每日,每周和“每月”:

WITH daily_avg AS (
    WITH total_min_max AS (SELECT
            COUNT(id) AS total_visits,
            MIN(date_time) AS first_date_time,
            MAX(date_time) AS last_date_time,
        FROM tb_user)
    SELECT total_visits/((last_date_time::date-first_date_time::date)+1) AS users_per_day
        FROM total_min_max)
SELECT
         users_per_day,
         (users_per_day * 7) AS users_per_week,
         (users_per_month * 30) AS users_per_month
    FROM daily_avg

话虽如此,从这些统计数据中得出的结论可能并不是很好,特别是如果你想看看它是如何变化的。

我还会将每天的数据标准化,而不是假设一个月内30天(如果不是每小时,因为并非所有日子都有24小时)。假设您在2011年1月每天有10次访问,在2011年2月每天有10次访问。这可以让您在1月份访问310次,在2月份访问次数为280次。如果您不注意,您可能会认为自己几乎有游客人数下降10%,所以2月出现了问题,实际情况并非如此。