枢轴内的窗口功能,有可能吗?

问题描述 投票:2回答:3

我有这张桌子

我需要创建一个枢轴,将情感显示为列,平均emotion_level按user_id,user_date,emotion分组。例如,对于user_id = 1,user_date = 2011-07-13和emotion ='Anger',平均emotion_level应为4.0。

我创建了一个支点:

select USER_ID, user_date,  
AVG(case emotion when 'Anger' then convert(float, emotion_level) else 0 end)  as Anger,
AVG(case emotion when 'Sadness' then convert(float, emotion_level) else 0 end) as Sadness,
AVG(case emotion when 'Interest' then convert(float, emotion_level) else 0 end) as Interest
from emotions group by USER_ID, user_date;

哪一半工作,但计算所有情绪中的平均情绪水平,但不计算用户,日期和情绪分组的情绪。

我的第一个用户的结果+情绪='愤怒'= 2,但它应该是4。

我想,我应该使用窗口函数(over(user by user_id,user_date,emotion)),但无法运行语法。

有可能吗?

我在prod中使用PostgreSQL 9,但上面的例子是用SQL Server编写的。

sql postgresql pivot window-functions
3个回答
1
投票
WITH    q (id, user_id, user_date, emotion, emotion_level) AS
        (
        VALUES
        (1, 1, '2011-07-13'::DATE, 'Anger', 3),
        (2, 1, '2011-07-13'::DATE, 'Anger', 5),
        (3, 1, '2011-07-13'::DATE, 'Sadness', 2),
        (4, 1, '2011-07-13'::DATE, 'Interest', 2),
        (5, 2, '2011-07-13'::DATE, 'Anger', 1),
        (6, 2, '2011-07-13'::DATE, 'Sadness', 4),
        (7, 2, '2011-07-13'::DATE, 'Sadness', 5),
        (8, 2, '2011-07-13'::DATE, 'Interest', 3),
        (9, 3, '2011-07-13'::DATE, 'Anger', 1),
        (10, 3, '2011-07-13'::DATE, 'Sadness', 3),
        (11, 3, '2011-07-13'::DATE, 'Interest', 4),
        (12, 3, '2011-07-13'::DATE, 'Interest', 5)
        ) 
SELECT  user_id, user_date,
        AVG(CASE emotion WHEN 'Anger' THEN emotion_level END)::numeric(3, 2) AS Anger,
        AVG(CASE emotion WHEN 'Sadness' THEN emotion_level END)::numeric(3, 2) AS Sadness,
        AVG(CASE emotion WHEN 'Interest' THEN emotion_level END)::numeric(3, 2) AS Interest
FROM    q
GROUP BY
        user_id, user_date
ORDER BY
        user_id, user_date

问题是你最初使用的表达式:

AVG(case emotion when 'Interest' then convert(float, emotion_level) else 0 end)

平均给定用户在给定日期的所有记录,并将非Interest条目视为0,而它们应被视为NULL,因此它们不会对Interest平均值有贡献。


1
投票

我首先在表中将'emotion_level'的数据类型更新为'float',然后使用pivot执行操作。如果未更新数据类型,则所需的值为int数据类型。

select user_id, user_date, Anger, Sadness, Interest 
from (select user_id,user_date,emotion, emotion_level 
from emotions) as emo
pivot(avg(emotion_level) 
for emotion in (Anger, Sadness, Interest)) as P;

以上查询的结果来自https://i.stack.imgur.com/y6ML3.png下面的链接


0
投票

我定义了一个CTE,然后join到它 - 你的主要问题可能是你不是grouping在emotion_level的事实。试试这个:

WITH average_emotion (user_id, date, emotion, average_level) as 
                     (SELECT user_id, user_date, emotion, AVG(convert(float, emotion_level))
                      FROM emotions
                      GROUP BY user_id, user_date, emotion)
SELECT a.user_id, a.user_date, COALESCE(b.average_level, 0) as Anger
FROM emotions as a
LEFT JOIN average_emotion as b
ON b.user_id = a.user_id
AND b.date = a.user_date
AND b.emotion = 'Anger'
GROUP BY a.user_id, a.user_date

然后,每次需要新列时,只需添加额外的left joins。

有许多方法可以对其进行重组,主要与您的数据模型的其余部分以及所需的输出相关。

© www.soinside.com 2019 - 2024. All rights reserved.