2017-08-08 44 views
1

我目前正在复制一个相当大的SQL聚合查询,以便我可以运行一次以返回整个数据集的度量标准,然后再对每天的度量标准进行分组。将SQL查询与共享逻辑结合

下面是计算总体指标的查询的简化示例。

SELECT 
    sum(sentiment) FILTER (WHERE user = :user) AS total_sentiment, 
    avg(sentiment) FILTER (WHERE user = :user) AS average_sentiment, 
    count(messages) FILTER (WHERE sender = :user) AS total_messages 
FROM 
    "Messages" 
WHERE 
    date >= :start AND date < :end; 

而这里是计算相同指标的计算方法,但每天计算一次。

SELECT 
    date_trunc('day', date) AS date, 
    sum(sentiment) FILTER (WHERE user = :user) AS total_sentiment, 
    avg(sentiment) FILTER (WHERE user = :user) AS average_sentiment, 
    count(messages) FILTER (WHERE sender = :user) AS total_messages 
FROM 
    "Messages" 
WHERE 
    date >= :start AND date < :end; 
GROUP BY 1 
ORDER BY 1 

有没有办法结合这两个查询,而不必重复大多数的逻辑?

以编程方式构建查询字符串是一个选项,但我绝对不会沿着那条路径走。

如果查询实际上和上面的例子一样简单,那么重复它们并不是一个问题,但它们处理更复杂的连接和统计功能 - 保持它们同步已经非常棘手。

理想情况下,输出将是一个表,其第一行包含整体指标,其余行将是每日计算。

回答

2

最简单的方法是使用grouping sets

SELECT date_trunc('day', date) AS date, 
     sum(sentiment) FILTER (WHERE user = :user) AS total_sentiment, 
     avg(sentiment) FILTER (WHERE user = :user) AS average_sentiment, 
     count(messages) FILTER (WHERE sender = :user) AS total_messages 
FROM "Messages" 
WHERE date >= :start AND date < :end 
GROUP BY GROUPING SETS ((), (date)); 
1

你可以使用窗口功能:

SELECT DISTINCT 
    date_trunc('day', date) AS date, 
    sum(sentiment) FILTER (WHERE user = :user) OVER() AS total_sentiment, 
    avg(sentiment) FILTER (WHERE user = :user) OVER() AS average_sentiment, 
    count(messages) FILTER (WHERE sender = :user) OVER() AS total_messages, 
    sum(sentiment) FILTER (WHERE user = :user) OVER(PARTITION BY date_trunc('day', date)) 
    AS total_sentiment_per_day, 
    ... 
FROM "Messages" 
WHERE date >= :start AND date < :end; 
ORDER BY 1