SQL语句帮助 - 为每个客户选择最新订单

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL语句帮助 - 为每个客户选择最新订单相关的知识,希望对你有一定的参考价值。

假设我有2个表:客户和订单。客户可以拥有多个订单。

现在,我需要向任何客户展示他最新的订单。这意味着如果客户有多个订单,则仅显示具有最新进入时间的订单。

这是我自己管理的程度:

SELECT a.*, b.Id
FROM Customer a INNER JOIN Order b ON b.CustomerID = a.Id
ORDER BY b.EntryTime DESC

这当然会返回所有拥有一个或多个订单的客户,首先显示每个客户的最新订单,这不是我想要的。此时我的思绪陷入了困境,所以我希望有人可以指出我正确的方向。

出于某种原因,我想我需要在某个地方使用MAX语法,但它现在就让我失望了。

更新:在这里经过几个答案后(有很多!),我意识到我犯了一个错误:我的意思是任何客户都有他的最新记录。这意味着如果他没有订单,那么我就不需要列出他。

UPDATE2:修复了我自己的SQL语句,这可能不会导致其他人混淆。

答案

我不认为您确实想要使用MAX(),因为您不想对OrderID进行分组。你需要的是一个带有SELECT TOP 1的有序子查询。

select * 
from Customers inner join Orders 
on Customers.CustomerID = Orders.CustomerID
and OrderID = (SELECT TOP 1 subOrders.OrderID 
                    FROM Orders subOrders 
                    WHERE subOrders.CustomerID = Orders.CustomerID 
                    ORDER BY subOrders.OrderDate DESC)
另一答案

虽然我看到你已经接受了答案,但我认为这个更直观:

select      a.*
           ,b.Id

from       customer a

inner join Order b
on         b.CustomerID = a.Id

where      b.EntryTime = ( select max(EntryTime)
                           from   Order
                           where  Id = b.Id
                         );

我必须通过执行计划来运行这样的事情以查看执行的差异,但是TOP函数在事后完成并且使用“order by”可能很昂贵,我相信使用max(EntryTime)将是运行此方法的最佳方式。

另一答案

这样的事情应该这样做:

SELECT X.*, Y.LatestOrderId
FROM Customer X
LEFT JOIN (
  SELECT A.Customer, MAX(A.OrderID) LatestOrderId
  FROM Order A
  JOIN (
    SELECT Customer, MAX(EntryTime) MaxEntryTime FROM Order GROUP BY Customer
  ) B ON A.Customer = B.Customer AND A.EntryTime = B.MaxEntryTime
  GROUP BY Customer
) Y ON X.Customer = Y.Customer

这假设同一客户的两个订单可能具有相同的EntryTime,这就是为什么在子查询MAX(OrderID)中使用Y以确保每个客户只发生一次。使用LEFT JOIN是因为您声明要显示所有客户 - 如果他们没有订单,那么LatestOrderId将是NULL

希望这可以帮助!

--

更新:-)这只显示订单的客户:

SELECT A.Customer, MAX(A.OrderID) LatestOrderId
FROM Order A
JOIN (
  SELECT Customer, MAX(EntryTime) MaxEntryTime FROM Order GROUP BY Customer
) B ON A.Customer = B.Customer AND A.EntryTime = B.MaxEntryTime
GROUP BY Customer
另一答案

您可以使用窗口功能。

SELECT *
  FROM (SELECT a.*, b.*,
               ROW_NUMBER () OVER (PARTITION BY a.ID ORDER BY b.orderdate DESC,
                b.ID DESC) rn
          FROM customer a, ORDER b
         WHERE a.ID = b.custid)
 WHERE rn = 1

对于每个客户(a.id),它会对所有订单进行排序并丢弃除最新订单之外的所有订单。 ORDER BY子句包括订单日期和条目ID,以防同一日期有多个订单。

通常,窗口函数比在大量记录上使用MAX()的任何查找要快得多。

另一答案
SELECT Cust.*, Ord.*
FROM Customers cust INNER JOIN Orders ord ON cust.ID = ord.CustID
WHERE ord.OrderID = 
    (SELECT MAX(OrderID) FROM Orders WHERE Orders.CustID = cust.ID)
另一答案

就像是:

SELECT
  a.*
FROM
  Customer a
    INNER JOIN Order b
      ON a.OrderID = b.Id
        INNER JOIN (SELECT Id, max(EntryTime) as EntryTime FROM Order b GROUP BY Id) met
          ON
            b.EntryTime = met.EntryTime and b.Id = met.Id
另一答案

我上面还没有看到的一种方法:

SELECT
     C.*,
     O1.ID
FROM
     dbo.Customers C
INNER JOIN dbo.Orders O1 ON
     O1.CustomerID = C.ID
LEFT OUTER JOIN dbo.Orders O2 ON
     O2.CustomerID = C.ID AND
     O2.EntryTime > O1.EntryTime
WHERE
     O2.ID IS NULL

这(以及我认为的其他解决方案)假设同一客户的两个订单不能具有完全相同的进入时间。如果这是一个问题,那么你必须做出选择,决定哪一个是“最新的”。如果这是一个问题发表评论,我可以扩展查询,如果需要考虑到这一点。

查询的一般方法是查找客户的订单,其中对于具有较晚日期的同一客户没有其他订单。根据定义,它是最新的订单。这种方法通常比使用派生表或子查询提供更好的性能。

另一答案

此查询比接受的答案快得多:

SELECT c.id as customer_id, 
    (SELECT co.id FROM customer_order co WHERE 
    co.customer_id=c.id 
    ORDER BY some_date_column DESC limit 1) as last_order_id
    FROM customer c

以上是关于SQL语句帮助 - 为每个客户选择最新订单的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:从多个客户的多个订单中选择最大的订单总数,并且每个订单上有多个项目

将第一个 SQL 选择语句结果用于第二个选择语句

客户和订单 Sql 语句

需要报告客户订单的最新状态,以及每个客户的每个订单状态的计数[关闭]

求助sql语句,多个join嵌套

为每个客户选择第一个和第 n 个订单