繁体   English   中英

SQL:按组汇总查询结果

[英]SQL: Sum the results of a query by group

几天前我刚刚开始学习 SQL,我正在研究一些基本的例子。 在这个例子中,我想找到我的朋友和队友喜欢的训练(基于我有多少朋友喜欢训练,有多少朋友完成了训练,以及我的朋友对训练的平均评分)。 到目前为止,我使用子查询为每次训练的每种类型的加权值获取加权值。 我想对每个训练的加权值求和,给每个训练一个总数,然后按总数对训练列表进行排序,并从中选择前几个。

这是我所做的。

SELECT training_id, (5* COUNT()) AS [value]FROM progress
WHERE user_id IN (SELECT friend_id AS user_ids FROM friendships WHERE user_id=6 UNION SELECT user_id FROM membership WHERE team_id IN (SELECT team_id FROM membership WHERE user_id = 6))
AND completed = 1
GROUP BY training_id

UNION ALL

SELECT training_id, (10 * AVG(rating))
FROM reviews
WHERE user_id IN (SELECT friend_id AS user_ids FROM friendships WHERE user_id=6 UNION SELECT user_id FROM membership WHERE team_id IN (SELECT team_id FROM membership WHERE user_id = 6))
GROUP BY training_id

UNION ALL

SELECT training_id, COUNT()
FROM likes
WHERE user_id IN (SELECT friend_id AS user_ids FROM friendships WHERE user_id=6 UNION SELECT user_id FROM membership WHERE team_id IN (SELECT team_id FROM membership WHERE user_id = 6))
GROUP BY training_id

结果如下:

training_id     value
______________________
1                10
2                5
1                34.5
2                45
1                6
2                3

如果您知道这样做的方法,或者是否有我应该考虑的替代方法,请告诉我。

(表'likes' 'reviews' 和'progress' 都包含字段“training_id”。你怎么看待加入这三个表开始?)

这相当令人印象深刻。 您的查询结构良好且易于阅读。 如果您想要每个 training_id 的总和,只需自己构建一个外部查询:

select training_id, sum(value)
from (<your query here>) x
group by training_id
order by sum(value) desc;

至于加入表格:不,通常你不想这样做。 您不想将每条进度记录与每条评论记录和每条training_id 的每条喜欢记录连接起来。 这将使您的值成倍增加(例如,一次培训的 2 个进度条目、3 条评论和 4 个赞将为您提供 2 x 3 x 4 = 24 条中间记录)。 在您的特定情况下,这不会有什么害处,因为AVG会产生相同的值,您可以将COUNT(*)替换为COUNT(DISTINCT progress_id)COUNT(DISTINCT likes_id) ,但是一旦您使用SUM您就会麻烦。

你可以做的是加入聚合:

with mates as
(
  select friend_id as user_id from friendships where user_id = 6
  union 
  select user_id from membership where team_id in 
               (select team_id from membership where user_id = 6)
)
select 
  training_id, 
  coalesce(p.value, 0) + 
  coalesce(r.value, 0) + 
  coalesce(l.value, 0) as total
from
(
  select training_id, 5 * count(*) as value
  from progress
  where user_id in (select user_id from mates)
  and completed = 1
  group by training_id
) p
full outer join
(
  select training_id, 10 * avg(rating) as value
  from reviews
  where user_id in (select user_id from mates)
  group by training_id
) r using (training_id)
full outer join
(
  select training_id, count(*) as value
  from likes
  where user_id in (select user_id from mates)
  group by training_id
) l using (training_id)
order by 2 desc;

好的,感谢您的输入。 我的第二个预感是对的。 我需要使用连接。 我只在文档中阅读了 Joins 并且不熟悉它们,但是一旦我尝试过它,它就非常简单。

这是解决方案。

SELECT training.*, ((10 * AVG(reviews.rating)) + COUNT(DISTINCT likes.user_id) + ( 5* COUNT(DISTINCT progress.trainee_id))) AS total FROM training JOIN likes ON training.training_id = likes.training_id JOIN reviews ON training.training_id = reviews.training_id JOIN progress ON training.training_id = progress.training_id WHERE user_id IN (SELECT friend_id AS user_ids FROM friendships WHERE user_id=6 UNION SELECT user_id FROM membership WHERE team_id IN (SELECT team_id FROM membership WHERE user_id = 6)) AND progress.completed = 1 AND progress.trainee_id IN (SELECT friend_id AS user_ids FROM friendships WHERE user_id=6 UNION SELECT user_id FROM membership WHERE team_id IN (SELECT team_id FROM membership WHERE user_id = 6)) ORDER BY total DESC GROUP BY training_name LIMIT 6

这给了我
training_id, training_name, total -- 这些是结果的字段名
1、初学者LiveCode,53
2、SQL 101、48

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM