使用 ANY/ALL 检索下订单数量最多的客户

and*_*rea 0 sql-server subquery greatest-n-per-group

我有这张表,我想检索下订单数量最多的客户。

我写了这个查询:

select * from customers where cust_id=(
select cust_id from orders
group by cust_id
having count(*)>=all(select count(cust_id)
                     from orders
                     group by cust_id))
Run Code Online (Sandbox Code Playgroud)

我知道也许有更好的方法来做到这一点,但我惊讶地发现 'ALL' 可以与 '> =' 一起使用

根据我的理解,'ALL' 检查当前行是大于还是小于子查询中的所有行,但我从没想过可以将它与 '=' 一起使用。

如果我将它与 '=' 或 '>' 一起使用,查询不会像我期望的那样返回任何行。

但是如果我将它们一起使用 '>=' 查询会给我正确的结果。

是不是很奇怪?

模式表

无论如何,最后我写了这个查询:

SELECT *
FROM Orders, customers
WHERE orders.cust_id=customers.cust_id
and orders.cust_id IN
            (SELECT TOP (1) o.cust_id
            FROM Orders AS O
            GROUP BY O.cust_id
            ORDER BY COUNT(*) DESC);
Run Code Online (Sandbox Code Playgroud)

你有更好或更优雅的解决方案吗?

在 'ALL' 子句中使用 '>=' 是不是很奇怪?

谢谢你。

ype*_*eᵀᴹ 6

各种写法。您的查询,稍微改写以使用JOIN并更正以在出现联系时返回所有客户:

select c.*, o.*
from customers as c
    join orders as o
      on o.cust_id = c.cust_id
where c.cust_id in 
      ( select cust_id 
        from orders
        group by cust_id
        having count(*) >=  
               all ( select count(*)
                     from orders
                     group by cust_id
                   )
      ) ;
Run Code Online (Sandbox Code Playgroud)

类似,不使用>= ALL

select c.*, o.*
from customers as c
    join orders as o
      on o.cust_id = c.cust_id
where c.cust_id in 
      ( select cust_id 
        from orders
        group by cust_id
        having count(*) =  
                  ( select top (1) count(*) as cnt
                     from orders
                     group by cust_id
                     order by cnt desc
                  )
      ) ;
Run Code Online (Sandbox Code Playgroud)

子查询简化为TOP WITH TIES

select c.*, o.* 
from customers as c
    join orders as o
      on o.cust_id = c.cust_id
where c.cust_id in 
      ( select top (1) with ties m.cust_id 
        from orders as m
        group by m.cust_id
        order by count(*) desc
      ) ;
Run Code Online (Sandbox Code Playgroud)

以上所有内容都可以重写为使用派生表或 CTE,并且JOIN子查询是不相关的。

另一种方法是结合使用窗口函数TOP

with 
  d as
  ( select c.*, o.*,
           cnt = count(*) over (partition by o.cust_id)  
    from customers as c
        join orders as o
          on o.cust_id = c.cust_id
  )
select top (1) with ties
    d.*
from d
order by d.cnt desc ; 
Run Code Online (Sandbox Code Playgroud)

或者只是窗口函数:

with 
  d as
  ( select m.cust_id,
           cnt = count(*)  
           max_cnt = max(count(*)) over ()  
    from orders as m
    group by m.cust_id
  )
select c.*, o.* 
from customers as c
    join orders as o
      on o.cust_id = c.cust_id
    join d 
      on d.cust_id = c.cust_id
where d.cnt = d.max_cnt ;
Run Code Online (Sandbox Code Playgroud)