我有一个名为workouts的表和另一个名为likesWorkouts的表。如果用户喜欢或不喜欢锻炼,那么我将用户ID,喜欢的锻炼的锻炼ID以及真或假插入名为likesWorkouts的表中。数据库结构与此问题SQL database structure for Like and DisLike
中接受的答案相同我正在尝试从锻炼表中检索锻炼,这些锻炼按照每个人的喜欢数量排序,但由于没有喜欢列,而且我可以获得锻炼的数量的唯一方法是做COUNT( *)在preferworkouts表中查询我应该按照他们喜欢的数量订购锻炼表吗?
修改
所以我让它工作唯一的问题是我有另一个名为Downloads的列表有两列userID
和WorkoutID
我需要获得一个训练的下载量,所以我添加了{{1}你的替代评级系统查询,但它导致喜欢和不喜欢的价值是错误的。知道为什么吗?
EDIT2:
所以我可以通过此查询获得下载
LEFT JOIN DownloadedWorkouts AS d ON w.ID = d.WorkoutID
如何将此添加到您的备用查询中?
答案 0 :(得分:7)
SELECT w.WorkoutID, COUNT(*) AS likeCount
FROM Workouts AS w
JOIN LikedWorkouts AS l
ON w.WorkoutID = l.WorkoutID
WHERE l.liked = TRUE -- You might need an alternative spelling of TRUE
GROUP BY w.WorkoutID
ORDER BY likeCount DESC; -- You might need ORDER BY COUNT(*) DESC
这并不能解释这些不喜欢的事情;排名最高的结果可能是一个有1000个喜欢和5000个不喜欢(其中一个有300个喜欢和0个不喜欢)。如果你想分别报告喜欢和不喜欢,或喜欢减去不喜欢的百分比,或喜欢与不喜欢的百分比,那么你必须修改查询,有时候从根本上适度。
这也没有显示任何根本不喜欢的锻炼(因为LikedWorkouts中的所有值都是FALSE,或者因为没有人对锻炼发表了意见)。有一些方法可以解决这个问题,但如果需要的话,需要更清楚地说明规范。
更完整的排名功能规格似乎是“喜欢的数量”除以“喜欢的数量加上不喜欢的数量”,其中没有喜欢或不喜欢的锻炼有0个喜欢和0个不喜欢(以及与没有喜欢或不喜欢的人会被视为有1000个不喜欢和不喜欢的锻炼。
为此,我倾向于使用TDQD - 测试驱动的查询设计。
SELECT WorkoutID,
SUM(CASE WHEN liked THEN 1 ELSE 0 END) AS likes,
SUM(CASE WHEN liked THEN 0 ELSE 1 END) AS dislikes
FROM LikedWorkouts
GROUP BY WorkoutID
这往往是特定于DBMS的,而SQL Server不是我的主要平台。最简单的方法是使用NVL或IFNULL等函数(以及LEFT JOIN)。 SQL Server似乎使用了IFNULL。
SELECT w.WorkoutID,
IFNULL(SUM(CASE WHEN l.liked THEN 1 ELSE 0 END), 0) AS likes,
IFNULL(SUM(CASE WHEN l.liked THEN 0 ELSE 1 END), 0) AS dislikes
FROM Workouts AS w
LEFT JOIN LikedWorkouts AS l ON w.WorkoutID = l.WorkoutID
GROUP BY WorkoutID
SELECT WorkoutID, likes / (likes + dislikes) AS rating
FROM (SELECT w.WorkoutID,
IFNULL(SUM(CASE WHEN l.liked THEN 1 ELSE 0 END), 0) AS likes,
IFNULL(SUM(CASE WHEN l.liked THEN 0 ELSE 1 END), 0) AS dislikes
FROM Workouts AS w
LEFT JOIN LikedWorkouts AS l ON w.WorkoutID = l.WorkoutID
GROUP BY WorkoutID
) AS r
ORDER BY 2; -- Or rating, or likes / (likes + dislikes)
有一个待解决的剩余问题 - 当给定锻炼没有评级时,除以零。
在某些方面,更好的排名功能会从喜欢的数量中减去不喜欢的数量,并除以喜欢和不喜欢的计数之和。然后没有排名的训练将在中间,排名为0%;只有不喜欢投票的锻炼将是-100%;而只有投票的锻炼将是+ 100%。只有最后一个查询需要更改,并且它生成的评级不是百分比,而只是一小部分-1.00 .. + 1.00。
SELECT WorkoutID, (likes - dislikes) / (likes + dislikes) AS rating
FROM (SELECT w.WorkoutID,
IFNULL(SUM(CASE WHEN l.liked THEN 1 ELSE 0 END), 0) AS likes,
IFNULL(SUM(CASE WHEN l.liked THEN 0 ELSE 1 END), 0) AS dislikes
FROM Workouts AS w
LEFT JOIN LikedWorkouts AS l ON w.WorkoutID = l.WorkoutID
GROUP BY WorkoutID
) AS r
ORDER BY 2; -- Or rating, or (likes - dislikes) / (likes + dislikes)
这有相同的除以零问题需要解决。
我认为(未经测试)你可以用以下方法解决除零问题:
SELECT WorkoutID,
CASE
WHEN (likes + dislikes) != 0
THEN (likes - dislikes) / (likes + dislikes)
ELSE 0
END AS rating
FROM (SELECT w.WorkoutID,
IFNULL(SUM(CASE WHEN l.liked THEN 1 ELSE 0 END), 0) AS likes,
IFNULL(SUM(CASE WHEN l.liked THEN 0 ELSE 1 END), 0) AS dislikes
FROM Workouts AS w
LEFT JOIN LikedWorkouts AS l ON w.WorkoutID = l.WorkoutID
GROUP BY WorkoutID
) AS r
ORDER BY 2; -- Or rating, or (likes - dislikes) / (likes + dislikes)
警告:所有SQL尚未在任何DBMS上测试,更不用说SQL Server了。
(注意:我通常避免ORDER BY 2
这是1986年SQL标准的一部分。许多DBMS允许您按选择列表中的列别名排序;其他DBMS可能要求您重复选择表达式中的表达式ORDER BY子句中的列表(这是违反DRY(不要重复自己)原则的一个令人遗憾的情况。使用ORDER BY 2
可能在大多数DBMS中起作用并绕过问题 - 但不是很理想。我不太清楚SQL Server是否足以知道它在这个问题上的影响范围。)
现在的问题表明这是计算下载量的一种方式:
SELECT *
FROM (SELECT w.ID,
IFNULL(SUM(CASE WHEN d.WorkoutID THEN 1 ELSE 0 END), 0) AS downloads
FROM UserWorkouts AS w
LEFT JOIN Profiles ON w.CreatorID = Profiles.UserID
LEFT JOIN DownloadedWorkouts AS d ON w.ID = d.WorkoutID
GROUP BY w.ID
) AS r;
围绕必要的查询包装SELECT * FROM (...) AS r
- 对于下载,您只需使用:
SELECT w.ID,
IFNULL(SUM(CASE WHEN d.WorkoutID THEN 1 ELSE 0 END), 0) AS downloads
FROM UserWorkouts AS w
LEFT JOIN Profiles ON w.CreatorID = Profiles.UserID
LEFT JOIN DownloadedWorkouts AS d ON w.ID = d.WorkoutID
GROUP BY w.ID
但是,此查询有三个新表;没有一个表明显对应于原始问题中的表。也许UserWorkouts就是之前的Workouts。我不明白为什么会介绍个人资料;看起来您应该只使用所有锻炼列表和DownloadedWorkouts表。 (将来,请至少为问题中的表格提供骨架模式;这将简化每个人的工作 - 为您翻译答案,并为我们提供答案。)
SELECT w.WorkoutID,
IFNULL(SUM(CASE WHEN d.WorkoutID THEN 1 ELSE 0 END), 0) AS downloads
FROM Workouts AS w
LEFT JOIN DownloadedWorkouts AS d ON w.WorkoutID = d.WorkoutID
GROUP BY w.ID
请注意,我已经使用了Workouts表,并假设主键列与以前一样是WorkoutID。
将其与主查询相结合,得出:
SELECT r.WorkoutID, r.Rating, d.Downloads
FROM (SELECT WorkoutID,
CASE
WHEN (likes + dislikes) != 0
THEN (likes - dislikes) / (likes + dislikes)
ELSE 0
END AS rating
FROM (SELECT w.WorkoutID,
IFNULL(SUM(CASE WHEN l.liked THEN 1 ELSE 0 END), 0) AS likes,
IFNULL(SUM(CASE WHEN l.liked THEN 0 ELSE 1 END), 0) AS dislikes
FROM Workouts AS w
LEFT JOIN LikedWorkouts AS l ON w.WorkoutID = l.WorkoutID
GROUP BY WorkoutID
) AS r1
) AS r
JOIN (SELECT w.ID AS WorkoutID,
IFNULL(SUM(CASE WHEN d.WorkoutID THEN 1 ELSE 0 END), 0) AS downloads
FROM Workouts AS w
LEFT JOIN DownloadedWorkouts AS d ON w.WorkoutID = d.WorkoutID
GROUP BY w.ID
) AS d
ON r.WorkoutID = d.WorkoutID
ORDER BY r.rating, d.WorkoutID;
这是TDQD实施的一个很好的示范。随着开发的进行,您可以创建和测试各种子查询,即使生成的查询相当复杂,也会得到可靠的答案。我不想尝试从头开始写这个最终查询;事实上,我不会 - 我会使用TDQD来获得正确的部件,就像所示。
注意:我仍然未经测试所有SQL。
答案 1 :(得分:1)
这样的事情:
SELECT w.*
FROM workouts w
LEFT OUTER JOIN (
SELECT workoutID,
cnt=COUNT(*)
FROM likedWorkouts
WHERE liked = 1
GROUP BY workoutID
) wl ON wl.workoutID = w.workoutID
ORDER BY wl.cnt DESC