从 SQL SELECT 中的子查询和 ROW_NUMBER 窗口函数生成“平均”列
Posted
技术标签:
【中文标题】从 SQL SELECT 中的子查询和 ROW_NUMBER 窗口函数生成“平均”列【英文标题】:Generate 'average' column from sub query and ROW_NUMBER window function in SQL SELECT 【发布时间】:2020-10-19 16:15:06 【问题描述】:我有以下 SQL Server 表(带有示例数据):
问卷调查
id | coachNodeId | youngPersonNodeId | complete
1 | 12 | 678 | 1
2 | 12 | 52 | 1
3 | 30 | 99 | 1
4 | 12 | 678 | 1
5 | 12 | 678 | 1
6 | 30 | 99 | 1
7 | 12 | 52 | 1
8 | 30 | 102 | 1
回答
id | questionnaireId | score
1 | 1 | 1
2 | 2 | 3
3 | 2 | 2
4 | 2 | 5
5 | 3 | 5
6 | 4 | 5
7 | 4 | 3
8 | 5 | 4
9 | 6 | 1
10 | 6 | 3
11 | 7 | 5
12 | 8 | 5
内容节点
id | text
12 | Zak
30 | Phil
52 | Jane
99 | Ali
102 | Ed
678 | Chris
我有以下 T-SQL 查询:
SELECT
Questionnaire.id AS questionnaireId,
coachNodeId AS coachNodeId,
coachNode.[text] AS coachName,
youngPersonNodeId AS youngPersonNodeId,
youngPersonNode.[text] AS youngPersonName,
ROW_NUMBER() OVER (PARTITION BY Questionnaire.coachNodeId, Questionnaire.youngPersonNodeId ORDER BY Questionnaire.id) AS questionnaireNumber,
score = (SELECT AVG(score) FROM Answer WHERE Answer.questionnaireId = Questionnaire.id)
FROM
Questionnaire
LEFT JOIN
ContentNode AS coachNode ON Questionnaire.coachNodeId = coachNode.id
LEFT JOIN
ContentNode AS youngPersonNode ON Questionnaire.youngPersonNodeId = youngPersonNode.id
WHERE
(complete = 1)
ORDER BY
coachNodeId, youngPersonNodeId
此查询输出以下示例数据:
questionnaireId | coachNodeId | coachName | youngPersonNodeId | youngPersonName | questionnaireNumber | score
1 | 12 | Zak | 678 | Chris | 1 | 1
2 | 12 | Zak | 52 | Jane | 1 | 3
3 | 30 | Phil | 99 | Ali | 1 | 5
4 | 12 | Zak | 678 | Chris | 2 | 4
5 | 12 | Zak | 678 | Chris | 3 | 4
6 | 30 | Phil | 99 | Ali | 2 | 2
7 | 12 | Zak | 52 | Jane | 2 | 5
8 | 30 | Phil | 102 | Ed | 1 | 5
解释一下这里发生了什么……有各种各样的教练,他们的工作是对各种年轻人进行问卷调查,并记录分数。教练可能会在以后对同一个年轻人重复几次问卷调查,希望他们得到更好的分数。我要达到的最终目标是教练的经理想看看教练的表现如何,所以他们想看看问卷的分数是否会上升。窗口函数代表了一种方法,用于确定同一教练/年轻人组合进行了多少次问卷调查。
我需要能够根据问卷编号确定平均分数。例如,教练“Zak”在他的第一份问卷(其中问卷编号 = 1)中记录了“1”和“3”分,因此平均值为 2。对于他的第二份问卷(其中问卷编号 = 2),分数为3' 和 '5' 所以平均值是 4。所以在分析这些数据时,我们知道随着时间的推移,Zak 的问卷分数已经从第一次的平均“2”提高到第二次的平均“4”。
我觉得查询需要按coachNodeId
和questionnaireNumber
值分组,所以它会输出类似这样的内容(我省略了questionnaireId
、youngPersonNodeId
、youngPersonName
和score
列,因为它们对输出并不重要——它们仅用于导出平均分数——并且对于结果的分组方式没有用处):
coachNodeId | coachName | questionnaireNumber | averageScore
12 | Zak | 1 | 2 (calculation: (1 + 3) / 2)
12 | Zak | 2 | 4 (calculation: (3 + 5) / 2)
12 | Zak | 3 | 4 (only one value: 4)
30 | Phil | 1 | 5 (calculation: (5 + 5) / 2)
30 | Phil | 2 | 2 (only one value: 2)
谁能建议我如何修改我的查询以根据子查询的分数和ROW_NUMBER
窗口函数输出平均分数?我已经达到了我的 SQL 技能的极限!
非常感谢。
【问题讨论】:
【参考方案1】:没有样本数据有点难以分辨,但我认为您描述的是聚合:
SELECT q.coachNodeId AS coachNodeId,
cn.[text] AS coachName,
q.youngPersonNodeId AS youngPersonNodeId,
ypn.[text] AS youngPersonName,
AVG(score)
FROM Questionnaire q JOIN
ContentNode cn
ON q.coachNodeId = cn.id JOIN
ContentNode ypn
ON q.youngPersonNodeId = ypn.id LEFT JOIN
Answer a
ON a.questionnaireId = q.id
WHERE complete = 1
GROUP BY q.coachNodeID, cn.[text] AS coachName,
q.youngPersonNodeId, ypn.[text]
【讨论】:
感谢@GordonLinoff,我添加了示例数据。一个相关的事情是“答案”表可能包含单个问卷的多个值,因此我使用子查询来平均这些值。答案表不包含youngPersonNodeId
或 coachNodeId
值,因此我们无法单独在该表中建立特定教练/年轻人组合的第一、第二、第三等问卷,因此我为什么使用ROW_NUMBER
函数来确定同一教练/年轻人组合进行问卷调查的次数。以上是关于从 SQL SELECT 中的子查询和 ROW_NUMBER 窗口函数生成“平均”列的主要内容,如果未能解决你的问题,请参考以下文章
SQL 编译错误:无法评估不受支持的子查询类型 - SELECT 子句中的函数调用
Oracle SQL,在 SELECT 标头中的子查询中返回唯一(最大)行(在 FROM、WHERE 之前)