我遇到了一个问题,我试图从每个组(日)或数据库中的记录中获取最高'n'条记录。经过一堆挖掘后,我发现了一些很棒的答案,事实上他们确实解决了我的问题。
然而,我的正义使我无法正确理解为什么这些“计数”解决方案有效。如果具有更好SQL知识的人可以解释,那将非常棒。
编辑:这里有更多细节
假设我有一个下面描述的表格和这个样本数据。 (为了简单起见,我有一个专栏跟踪下一个即将到来的午夜的时间,以便更好地将“每天”分组。)
id | vote_time | time_of_midnight | name | votes_yay | votes_nay
------------------------------------------------------------------------
1 | a | b | Person p | 24 | 36
1 | a | b | Person q | 20 | 10
1 | a | b | Person r | 42 | 22
1 | c | d | Person p | 8 | 10
1 | c | d | Person s | 120 | 63
我正在尝试按降序计算每天投票数最多的前5名。我能够使用引用的文章创建一个可以给我的查询以下结果(在Oracle上):
SELECT name, time_of_midnight, votes_yay, votes_nay, (votes_yay+votes_nay) AS total_votes
FROM results a
WHERE id=1 AND (
SELECT COUNT(*)
FROM results b
WHERE b.id=a.id AND b.time_of_midnight=a.time_of_midnight AND (a.votes_yay+a.votes_nay) >= (b.votes_yay+b.votes_nay)) <= 5
ORDER BY time_of_midnight DESC, total_votes DESC;
name | time_of_midnight | votes_yay | votes_nay | total_votes
------------------------------------------------------------------------
Person s | d | 120 | 63 | 183
Person p | d | 8 | 10 | 18
Person r | b | 42 | 22 | 64
Person p | b | 24 | 36 | 60
Person q | b | 20 | 10 | 30
所以我不太确定
name
以确保它不会错误地加入数据?答案 0 :(得分:1)
让我们从您的查询实际计算具有最低投票数的前5个名称开始。要获得最高编号的前5名,您需要更改此条件:
(a.votes_yay+a.votes_nay) >= (b.votes_yay+b.votes_nay)
进入这个:
(a.votes_yay+a.votes_nay) <= (b.votes_yay+b.votes_nay)
或者,也许,这(相同):
(b.votes_yay+b.votes_nay) >= (a.votes_yay+a.votes_nay)
(后一种形式在我看来更可取,但仅仅因为它与其他两个比较一致,左侧有b
列,而a
列上有results
列。右侧。这与逻辑的正确性完全无关。)
从逻辑上讲,发生了什么事。对于id
中的每一行,服务器将在同一个表中查找与给定行的time_of_midnight
和(id, time_of_midnight)
匹配且具有相同或更高总票数超过给定行数。然后,它将对找到的行进行计数,并检查结果是否不大于5,即如果同一count <= 5
组中的不超过5行的投票数与给定行中的相同或更高。
例如,如果给定的行恰好是其组中投票最多的行,则子查询将只找到相同的行(假设没有关系),因此计数将为1.即小于5 - 因此,给定的行将有资格获得输出。
如果给定的行将是组中投票次数第二的项,则子查询将找到相同的行和顶部投票的项目(再次,假设没有关联),这将给出count。再次,匹配SELECT name, time_of_midnight, votes_yay, votes_nay, (votes_yay+votes_nay) AS total_votes
FROM results a
WHERE id=1 AND (
SELECT COUNT(*) + 1
FROM results b
WHERE b.id=a.id AND b.time_of_midnight=a.time_of_midnight
AND (b.votes_yay+b.votes_nay) > (a.votes_yay+a.votes_nay)) <= 5
ORDER BY time_of_midnight DESC, total_votes DESC;
条件,因此该行将在输出中返回。
通常,如果某行根据总投票数在其组中排名为# N ,则表示该组中有 N 行投票号与给定行中的号码相同或更高(我们仍假设没有联系)。因此,当您以这种方式计算投票时,您实际上是在计算给定行的排名。
现在,如果存在关系,则使用此方法可能会减少每组的结果。实际上,如果一个组在最大行数上绑定了6行或更多行,那么输出中的该组将得到 no rows ,因为子查询永远不会返回小于6的计数值
这是因为实际上所有排名靠前的项目都会被排名为6(或者不管它们的数量是多少)而不是1.要将它们排名为1,您可以尝试对同一查询进行以下修改:< / p>
{{1}}
现在,子查询将仅查找 ,以获得投票数高于给定行的行。结果计数将增加1,这将是给定行的排名(以及与5进行比较的值)。
所以,如果计数是例如10,10,8,7等等,排名将计算为1,1,3,4等,而不是原始版本的2,2,3,4等。
当然,这意味着输出现在可能更多,而不是每组5行。例如,如果投票分配为10,9,8,8,8,8,6等,你将获得10,9和所有8(因为排名将是1,2,3,3,3, 3,7 ......)。要为每个组返回完全 5个名称(假设其中至少有5个),您可能需要完全考虑不同的方法。