【问题标题】:join just last record in second table, but include records don't have match in second table仅加入第二个表中的最后一条记录,但包含第二个表中不匹配的记录
【发布时间】:2014-03-03 21:49:24
【问题描述】:

我知道有很多类似的问题。实际上我使用了this,它可以工作,但我不知道如何包含第二个表中不匹配的记录。

我在 MS SQL Server 上使用示例 Northwind db。

使用这个查询:

SELECT Customers.CustomerID, Customers.CompanyName, Orders.OrderID, Orders.OrderDate
FROM Customers
LEFT OUTER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
INNER JOIN
    (
        SELECT CustomerID, MAX(OrderDate) maxDate
        FROM Orders
        GROUP BY CustomerID
    ) b ON Orders.CustomerID = b.CustomerID AND
            Orders.OrderDate = b.maxDate
ORDER BY Orders.OrderDate 

我得到正确的结果,但缺少不匹配的记录。

如果我使用 LEFT OUTER JOIN 代替 INNER JOIN:

SELECT Customers.CustomerID, Customers.CompanyName, Orders.OrderID, Orders.OrderDate
FROM Customers
LEFT OUTER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
LEFT OUTER JOIN
    (
        SELECT CustomerID, MAX(OrderDate) maxDate
        FROM Orders
        GROUP BY CustomerID
    ) b ON Orders.CustomerID = b.CustomerID AND
            Orders.OrderDate = b.maxDate
ORDER BY Orders.OrderDate 

我丢失了记录,但在这种情况下我重复了客户名称。

我想要:获取只有他最后一个订单的客户列表,如果他没有订单,他的名字无论如何都应该出现。

【问题讨论】:

  • 您确定不会在内部联接中获得重复的客户名称吗?
  • 不,没有,只需使用 ORDER BY Customers.CustomerID 运行即可检查。
  • 看来我在这里找到了解决方案:stackoverflow.com/questions/11764413/…
  • 。 .我不明白为什么左外连接会导致重复的客户名称。 left outer join 是一种解决方案,尽管窗口函数是更好的解决方案。

标签: sql sql-server join


【解决方案1】:

我用这个answer 来解决这个问题。

查看代码:

select Customers.CustomerID, Customers.CompanyName, Orders.OrderID, Orders.OrderDate
 from Customers
left outer join  Orders ON Customers.CustomerID=Orders.CustomerID
where   Orders.OrderDate is null OR
       Orders.OrderDate = 
       ( SELECT MAX(OrderDate)
           FROM Orders
          WHERE Customers.CustomerID=Orders.CustomerID)       
ORDER BY Customers.CustomerID 

这正是我想要的。

更新:最好使用 OrderID 而不是 OrderTime:

select Customers.CustomerID, Customers.CompanyName, Orders.OrderID, Orders.OrderDate
 from Customers
left outer join  Orders ON Customers.CustomerID=Orders.CustomerID
where   Orders.OrderID is null OR
       Orders.OrderID = 
       ( SELECT MAX(OrderID)
           FROM Orders
          WHERE Customers.CustomerID=Orders.CustomerID)       
ORDER BY Customers.CustomerID 

【讨论】:

    【解决方案2】:

    执行此操作的最佳方法是使用 ROW_NUMBER() 进行 CTE,此查询将具有更好的成本,因为您只访问 Orders 表一次而不是两次来获取数据,一次获取最大记录。

    WITH    LastOrder
              AS ( SELECT CustomerID
                       ,OrderID
                       ,OrderDate
                       ,ROW_NUMBER() OVER ( PARTITION BY CustomerID ORDER BY OrderDate DESC ) AS RowNum
                    FROM Orders)
        SELECT c.CustomerID
               ,c.CompanyName
               ,lo.OrderID
               ,lo.OrderDate
            FROM Customers AS c
            LEFT OUTER JOIN LastOrder AS lo
                ON c.Customer_id = lo.CustomerID
                   AND lo.RowNum = 1
    

    【讨论】:

    • 不,它显示不同订单的重复客户名称
    • @Alex 我必须修复我的PARTITION BY 子句。需要从中删除 OrderID。现在它应该只显示最后一个订单。
    【解决方案3】:

    您有重复的客户名称,因为您的链接超过了订单日期。因此,如果您在某个客户的最后日期有两个或更多订单,您将获得所有这些最后的订单。 如果我假设 orderid 与 orderdate 具有相同的顺序,那么下面的语句应该只为每个客户返回一行。

    select cs.*, o.* from customers cs
    left outer join (
      select customerid, max(orderid) as orderid from orders
      group by customerid
    ) lnk on cs.customerid = lnk.customerid
    left outer join orders o on lnk.orderid = o.orderid
    order by cs.customerid
    

    【讨论】:

    • OrderID 是对的,我在查询中做了这些更改。
    猜你喜欢
    • 2017-08-17
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 2013-07-23
    • 2021-03-09
    • 1970-01-01
    相关资源
    最近更新 更多