SQL:如何通过加入来排序和限制

时间:2018-03-07 00:24:35

标签: sql postgresql

举个例子,假设我有以下问题:

select
  u.id,
  u.name,
  (select s.status from user_status s where s.user_id = u.id order by s.created_at desc limit 1) as status
from
  user u
where
  u.active = true;

以上查询效果很好。它返回所选用户的最新用户状态。但是,我想知道如何使用user_status表上的连接获得相同的结果,而不是使用子查询。这样的事情可能吗?

我正在使用PostgreSQL。

感谢您提供任何帮助!

4 个答案:

答案 0 :(得分:0)

 select u.id , b.status 
 from user u join user_status b on u.id= b.user_id
 where u.active = true;
 order by b.s.created_at desc limit 1

我认为这项工作。 但在你的代码中有“b”,我不知道它是什么。

答案 1 :(得分:0)

JOIN语法不直接提供订单或限制作为选项;所以严格来说,你不能直接实现你想要的加入。我认为解决问题的最简单方法是使用连接子查询,如下所示:

select
       u.id
     , u.name
     , s.status
from user u
left join (
          select
               user_id
             , status
             , row_number() over(partition by user_id
                                 order by created_at desc) as rn
          from user_status s
          ) s on u.id = s.userid and s.rn = 1
where u.active = true;

此处,分析函数row_number()over()子句相结合,使后续连接条件and s.rn=1能够通过计算rn值来利用排序和限制连接行。

nb select子句中的相关子查询(在问题的查询中使用)就像左连接一样,因为它可以返回NULL。如果不需要或不需要该效果,您可以更改为内部联接。

可以将子查询移动到CTE中,但除非有令人信服的理由这样做,否则我更喜欢使用上面提到的更传统的形式。

另一种方法(Postgres 9.3或更高版本的 )是使用lateral连接,它与原始子查询非常相似,但因为它成为from子句的一部分很可能在select子句中使用该子查询更有效率。

select
       u.id
     , u.name
     , s.status
from user u
left join lateral (
       select user_status.status 
       from user_status
       where user_status.user_id = u.id 
       order by user_status.created_at desc 
       limit 1
       ) s ON true
where u.active = true;

答案 2 :(得分:0)

我最终做了以下工作,这对我很有帮助:

select
  u.id,
  u.name,
  us.status
from
  user u
  left join (
    select
      distinct on (user_id)
      *
    from
      user_status
    order by
      user_id,
      created_at desc
  ) as us on u.id = vs.user_id
where
  u.active = true;

这比我在问题中的查询更有效。

答案 3 :(得分:-1)

您可以通过将子查询转换为with子句并在连接中使用它来实现它