SQL:按组查询查询结果

时间:2015-10-07 08:33:08

标签: mysql sql sql-server sqlite

我几天前刚刚开始学习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

如果您知道如何做到这一点,或者我应该关注这种方法的替代方法,请告诉我。

(表格'喜欢''评论'和'进展'都包含字段“training_id”。你怎么看待加入这三个表开始?)

2 个答案:

答案 0 :(得分:0)

这令人印象深刻。您的查询结构良好且易于阅读。如果你想要每个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),但一旦您和#39;使用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;

答案 1 :(得分:0)

好的,谢谢你的意见。我第二次预感是正确的。我需要使用联接。我只阅读了文档中的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