从列表第2部分中的每个帐户ID获取一行

时间:2020-03-06 14:42:01  来源:igfitidea点击:

不确定如何提出SO后续措施,但这是参考先前的问题:
从列表中为每个帐户ID提取一行

我正在使用的查询是:

SELECT *
FROM scores s1
WHERE accountid NOT IN (SELECT accountid FROM scores s2 WHERE s1.score < s2.score)
ORDER BY score DESC

这将选择最高分,并将结果限制为每个帐户ID一行;他们的最高分。

最后一个障碍是,此查询将返回具有最高得分多次出现的帐户ID的多行。因此,如果帐户id 17的得分分别为40、75、30、75,则查询将返回得分为75的两行。

任何人都可以修改此查询(或者提供更好的查询)来解决此问题,并将每个帐户ID真正限制为一行吗?

再次感谢!

解决方案

如果要选择列的子集,则可以使用DISTINCT关键字来过滤结果。

SELECT DISTINCT UserID, score
FROM scores s1
WHERE accountid NOT IN (SELECT accountid FROM scores s2 WHERE s1.score < s2.score)
ORDER BY score DESC

数据库支持不同吗?如在选择与y不同的x?

select accountid, max(score) from scores group by accountid;

如果RDBMS支持它们,那么分析功能将是一种很好的方法,尤其是在我们需要该行的所有列的情况下。

select ...
from   (
   select accountid,
          score,
          ...
          row_number() over 
               (partition by accountid
                    order by score desc) score_rank
   from   scores)
where score_rank = 1;

在我们描述的情况下,返回的行是不确定的,但是我们可以轻松地修改分析函数,例如,通过对(score desc,test_date desc)进行排序来获取两个匹配的高分中的最新者。

其他基于等级的分析功能也将达到类似的目的。

如果我们不介意重复,那么以下内容可能会比我们当前的方法更有效:

select ...
from   (
   select accountid,
          score,
          ...
          max(score) over (partition by accountid) max_score
   from   scores)
where score = max_score;

如果我们只对科目编号和分数感兴趣,则可以使用上面Paul给出的简单GROUP BY查询。

SELECT accountid, MAX(score) 
FROM scores 
GROUP BY accountid;

如果需要分数表中的其他属性,则可以通过查询从行中获取其他属性,如下所示:

SELECT s1.*
FROM scores AS s1
  LEFT OUTER JOIN scores AS s2 ON (s1.accountid = s2.accountid 
    AND s1.score < s2.score)
WHERE s2.accountid IS NULL;

但这仍然会提供多行,在示例中,给定帐户ID的两个分数与其最大值匹配。要将结果集进一步减少为单个行,例如具有最新游戏日期的行,请尝试以下操作:

SELECT s1.*
FROM scores AS s1
  LEFT OUTER JOIN scores AS s2 ON (s1.accountid = s2.accountid 
    AND s1.score < s2.score)
  LEFT OUTER JOIN scores AS s3 ON (s1.accountid = s3.accountid 
    AND s1.score = s3.score AND s1.gamedate < s3.gamedate) 
WHERE s2.accountid IS NULL
    AND s3.accountid IS NULL;

该解决方案在MS SQL中有效,为我们提供了整行。

SELECT *
FROM scores
WHERE scoreid in
(
  SELECT max(scoreid)
  FROM scores as s2
    JOIN
  (
    SELECT max(score) as maxscore, accountid
    FROM scores s1
    GROUP BY accountid
  ) sub ON s2.score =  sub.maxscore AND s2.accountid = s1.accountid
  GROUP BY s2.score, s2.accountid
)