2008-12-01 163 views
7

假设我有2个表格:Customers和Orders。客户可以有许多订单。SQL语句帮助 - 为每个客户选择最新订单

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

这是我对我自己有多远管理:

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

当然这将返回所有客户与一个或更多的订单,首先显示的每个客户,这不是我想要的最新订单。我的思想在这一点上陷入了一种尴尬的局面,所以我希望有人能够指引我正确的方向。

出于某种原因,我认为我需要在某处使用MAX语法,但它现在只是逃避我。

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

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

+0

您的客户表具有的OrderId。是对的吗? – 2008-12-01 16:43:24

+0

是的,正如SQL中所暗示的那样。 – alextansc 2008-12-01 16:51:54

+0

如果您的客户表有一个OrderID,您的问题就没有意义。如果确实如此,你会说每一份订单都有不同的客户。你确定你的Order表没有CustomerID吗? – 2008-12-01 17:24:16

回答

8

我不认为你想使用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) 
0
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) 
+0

您正在使用Max OrderID获取订单,而不是Max EntryTime,它可能不同。 – 2008-12-01 17:06:22

3

像这样的东西应该这样做:

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

希望这会有所帮助!

-

UPDATE :-)这说明只有客户订单:

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 
+0

该解决方案比OP选择的解决方案快得多。 – 2017-08-17 02:07:32

0

喜欢的东西:

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 
6

虽然我看你已经接受了答案,我想这是一个多一点直观:

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)将是运行这个最好的方法。

1

您可以使用窗口功能。

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()对大量记录进行查找要快得多。我没有上面没有看到

0

一种方法:

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 

这(以及其他的解决方案,我相信),假定没有两个订单为相同的客户可以有相同的进入时间。如果这是一个问题,那么你将不得不作出决定哪一个是“最新”的选择。如果这是发表评论的问题,并且我可以扩展查询以解决该问题。

查询的一般方法是找到客户的订单,其中没有针对具有较晚日期的同一客户的另一个订单。这是根据定义的最新订单。这种方法通常会提高性能,然后使用派生表或子查询。

0

该查询比接受的答案快得多:在这个例子中

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