无极限的解决方案

发布于 2025-01-12 10:09:54 字数 1476 浏览 0 评论 0原文

我有一个这样的表(来自LeetCode):

requester_idAccepter_idAccept_date
122016/06/03
132016/06/08
232016/06/08
342016/06/09

找到拥有最多朋友的人以及最多的好友数量。

预期输出:

idnum
33

我编写了这个查询来获取答案,它有效:

select a.f as "id", count(a.f) as "num"
from (
    select requester_id as f
    from requestaccepted
    union all
    select accepter_id as f
    from requestaccepted ) a
group by a.f
order by count(a.f) desc
limit 1;

我并不 100% 相信使用 limit 1 是最好的解决方案。

替代/更好的选择应该是什么?

I have a table like this (from LeetCode):

requester_idaccepter_idaccept_date
122016/06/03
132016/06/08
232016/06/08
342016/06/09

Find the people who have the most friends and the most friends number.

Expected Output:

idnum
33

I wrote this query for the answer and it works:

select a.f as "id", count(a.f) as "num"
from (
    select requester_id as f
    from requestaccepted
    union all
    select accepter_id as f
    from requestaccepted ) a
group by a.f
order by count(a.f) desc
limit 1;

I am not 100% convinced using limit 1 is the best solution.

What should be an alternative/better option?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

淡淡離愁欲言轉身 2025-01-19 10:09:54

ORDER BY 之后的 LIMIT 1 就可以获得单个获胜者:

SELECT a.id, count(*) AS num
FROM  (
   SELECT requester_id AS id FROM requestaccepted
   UNION ALL
   SELECT accepter_id  AS id FROM requestaccepted
   ) a
GROUP  BY a.id
ORDER  BY num DESC
LIMIT  1;

如果有多个获胜者,您将获得任意选择。您可以添加其他 ORDER BY 表达式来获得确定性选择。

LIMIT / FETCH FIRST (真的吗?),窗口函数 row_number() 是一个(更昂贵!)替代方案:

SELECT id, num
FROM  (
   SELECT a.id, count(*) AS num
        , row_number() OVER (ORDER BY count(*) DESC) AS rn
   FROM  (
      SELECT requester_id AS id FROM requestaccepted
      UNION ALL
      SELECT accepter_id  AS id FROM requestaccepted
      ) a
   GROUP BY a.id
   ) sub
WHERE  rn = 1;

如果您必须避免 所有获胜的 ID,只需添加 WITH TIES。必须使用标准 SQL 语法 FETCH FIRST 1 ROWS 而不是 Postgres 快捷方式 LIMIT 1 来添加该子句。

SELECT a.id, count(*) AS num
FROM  (
   SELECT requester_id AS id FROM requestaccepted
   UNION ALL
   SELECT accepter_id  AS id FROM requestaccepted
   ) a
GROUP  BY a.id
ORDER  BY count(*) DESC
FETCH  FIRST 1 ROWS WITH TIES;

无需额外的 ORDER BY 表达式来解决关系。

如果您必须避免 LIMIT / FETCH FIRST(真的吗?),窗口函数 rank() 是一个(更昂贵!)替代方案:

SELECT id, num
FROM  (
   SELECT a.id, count(*) AS num
       , rank() OVER (ORDER BY count(*) DESC) AS rnk
   FROM  (
      SELECT requester_id AS id FROM requestaccepted
      UNION ALL
      SELECT accepter_id  AS id FROM requestaccepted
      ) a
   GROUP  BY a.id
   ) sub
WHERE  rnk = 1
ORDER  BY id; -- optional

db>>小提琴此处 - 带有扩展测试用例以显示平局

请参阅:

  • 获取具有最高值且有联系的顶行
  • <一个href="https://stackoverflow.com/questions/9629953/postgresql-equivalent-for-top-n-with-ties-limit-with-ties/9630562#9630562">PostgreSQL 等价于 TOP n WITH TIES: LIMIT "有关系”?

LIMIT 1 after ORDER BY is just fine to get a single winner:

SELECT a.id, count(*) AS num
FROM  (
   SELECT requester_id AS id FROM requestaccepted
   UNION ALL
   SELECT accepter_id  AS id FROM requestaccepted
   ) a
GROUP  BY a.id
ORDER  BY num DESC
LIMIT  1;

You get an arbitrary pick if there are multiple winners. You might add additional ORDER BY expressions to get a deterministic pick.

If you must avoid LIMIT / FETCH FIRST (really?) the window function row_number() is a (more expensive!) alternative:

SELECT id, num
FROM  (
   SELECT a.id, count(*) AS num
        , row_number() OVER (ORDER BY count(*) DESC) AS rn
   FROM  (
      SELECT requester_id AS id FROM requestaccepted
      UNION ALL
      SELECT accepter_id  AS id FROM requestaccepted
      ) a
   GROUP BY a.id
   ) sub
WHERE  rn = 1;

To get all IDs that tie for the win, just add WITH TIES. Must use standard SQL syntax FETCH FIRST 1 ROWS instead of the Postgres shortcut LIMIT 1 to add the clause.

SELECT a.id, count(*) AS num
FROM  (
   SELECT requester_id AS id FROM requestaccepted
   UNION ALL
   SELECT accepter_id  AS id FROM requestaccepted
   ) a
GROUP  BY a.id
ORDER  BY count(*) DESC
FETCH  FIRST 1 ROWS WITH TIES;

No additional ORDER BY expressions, that would resolve ties.

If you must avoid LIMIT / FETCH FIRST (really?) the window function rank() is a (more expensive!) alternative:

SELECT id, num
FROM  (
   SELECT a.id, count(*) AS num
       , rank() OVER (ORDER BY count(*) DESC) AS rnk
   FROM  (
      SELECT requester_id AS id FROM requestaccepted
      UNION ALL
      SELECT accepter_id  AS id FROM requestaccepted
      ) a
   GROUP  BY a.id
   ) sub
WHERE  rnk = 1
ORDER  BY id; -- optional

db<>fiddle here - with extended test case to show a tie

See:

猥︴琐丶欲为 2025-01-19 10:09:54

由于您只需要数量最多的朋友,因此您可以直接获取接受的 id 的数量,并且最多可以使用。

select  id ,max(num) from
(
select accepter_id id ,count(*) num from requestaccepted
group by accepter_id 
) a

As you just need friends with highest count, you can directly get count of accepted id, and max of that will work.

select  id ,max(num) from
(
select accepter_id id ,count(*) num from requestaccepted
group by accepter_id 
) a
四叶草在未来唯美盛开 2025-01-19 10:09:54

另一种有趣的方法是使用 Join LateralLimit

架构并插入语句:

 create table requestaccepted(requester_id int, accepter_id int, accept_date date);
 insert into requestaccepted values(1,  2,  '2016/06/03');
 insert into requestaccepted values(1,  3,  '2016/06/08');
 insert into requestaccepted values(2,  3,  '2016/06/08');
 insert into requestaccepted values(3,  4,  '2016/06/09');

Output:

 SELECT id,count(*)num
 FROM requestaccepted r
 JOIN LATERAL (VALUES(r.requester_id),(r.accepter_id)) s(id) ON TRUE
 group by id
 order by num desc
 Limit 1 

Output:

idnum
33

db<>fiddle 此处

Another interesting way could be using Join Lateral with Limit

Schema and insert statements:

 create table requestaccepted(requester_id int, accepter_id int, accept_date date);
 insert into requestaccepted values(1,  2,  '2016/06/03');
 insert into requestaccepted values(1,  3,  '2016/06/08');
 insert into requestaccepted values(2,  3,  '2016/06/08');
 insert into requestaccepted values(3,  4,  '2016/06/09');

Output:

 SELECT id,count(*)num
 FROM requestaccepted r
 JOIN LATERAL (VALUES(r.requester_id),(r.accepter_id)) s(id) ON TRUE
 group by id
 order by num desc
 Limit 1 

Output:

idnum
33

db<>fiddle here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文