繁体   English   中英

SQL左连接:选择一对多关系中的最后一个记录

[英]SQL Left join: selecting the last records in a one-to-many relationship

我有一个客户表和一个详细信息表。

我想要为表中的每个客户提取记录,并在适用的情况下显示该客户的最新详细数据。

目前我的where子句正在筛选出客户。

我已经尝试将where子句移动到左外连接中,但是我无法获得所需的结果。

在运行查询时,它似乎根本不会过滤产品。

SELECT
    cust.Customer
  , cust.Company
  , inv.Date
  , inv.Product
  , inv.Units
  , inv.Extended 
FROM
  customerlist cust
LEFT OUTER JOIN 
  detail inv 
ON 
  cust.customer = inv.customer
LEFT OUTER JOIN 
  detail inv2 
ON 
      inv.customer = inv2.customer 
  AND (
          inv.date < inv2.date 
       OR inv.date = inv2.date AND inv.customer < inv2.customer
      )
WHERE 
      (
          inv.Product = 'CC' 
       OR inv.Product = 'CG' 
       OR inv.Product = 'CH'
      ) 
  AND inv2.customer IS NULL

我的问题类似于

SQL连接:选择一对多关系中的最后一条记录

我正在尝试同样的事情,只想包括每个客户和按产品过滤。

更新

样本数据

这是我的原始查询,除了我缺少客户外,这是很好的

这是我的原始查询

如果我删除where子句并将其插入左连接,如下所示

LEFT OUTER JOIN 
  detail inv2 
ON 
      inv.customer = inv2.customer 
  AND (
           inv.date < inv2.date 
       OR  inv.date = inv2.date AND inv.customer < inv2.customer
      ) 
  AND (    
           inv.Product = 'CC' 
       OR  inv.Product = 'CHECK' 
       OR  inv.Product = 'ACH'
      )

结果如下所示产品列不是“CC”等。客户是重复的。

在此输入图像描述

你几乎是对的。

您的第一个查询将删除所有没有指定产品详细信息的客户,因为您没有在第一个OUTER JOINON条件中指定产品过滤器。

SELECT
    cust.Customer
  , cust.Company
  , inv.Date
  , inv.Product
  , inv.Units
  , inv.Extended 
FROM
  customerlist cust
LEFT OUTER JOIN 
  detail inv 
ON 
      cust.customer = inv.customer
  AND inv.Product IN ('CC', 'CG', 'CH')
LEFT OUTER JOIN 
  detail inv2 
ON 
      inv.customer = inv2.customer 
  AND (
          inv.date < inv2.date 
       OR inv.date = inv2.date AND inv.customer < inv2.customer
      )
WHERE 
  inv2.customer IS NULL

应该这样做。

还有一件事我觉得不太正确。 AND inv.customer < inv2.customer部分应该是AND inv.id < inv2.id (如果detail表中有id字段)。

这是因为OR条件是通过主键过滤具有相同日期的detail记录。

UPDATE

由于有问题的表没有主键字段,您可以使用ROWID ADS功能来解决:

SELECT
    cust.Customer
  , cust.Company
  , inv.Date
  , inv.Product
  , inv.Units
  , inv.Extended 
FROM
  customerlist cust
LEFT OUTER JOIN 
  detail inv 
ON 
      cust.customer = inv.customer
  AND inv.Product IN ('CC', 'CG', 'CH')
LEFT OUTER JOIN 
  detail inv2 
ON 
      inv.customer = inv2.customer 
  AND (
          inv.date < inv2.date 
       OR inv.date = inv2.date AND inv.ROWID < inv2.ROWID
      )
WHERE 
  inv2.customer IS NULL

您的第二个LEFT JOIN是为了在客户最近之前排除订单? 我将其重写为EXISTS 我不熟悉Advantage DataBase,希望它的SQL实现并不罕见。

SELECT
    Cust.Customer,
    Cust.Company,
    Inv.Date,
    Inv.Product,
    Inv.Units,
    Inv.Extended 
FROM
    customerlist AS Cust
    LEFT JOIN detail AS Inv ON Cust.customer = Inv.customer
WHERE
        (Inv.Product = 'CC' OR Inv.Product = 'CG' OR Inv.Product = 'CH')
    AND NOT EXISTS (SELECT * FROM detail AS Inv2 WHERE Cust.customer = Inv2.customer AND Inv2.date > inv.date)

假设Advantage支持IN ,您可以通过将X = 'A' OR X = 'B'替换为X IN ('A', 'B')来简化。


请注意,如上所述,这表示客户的最新订单类型为“CC”,“CG”或“CH”。 如果目标是向客户显示该类型的最新订单,即使他们具有其他类型的后续订单,也需要进行调整。

例如,如果Bob已经购买了AB,BC,CC和DE,则他将被排除在上述查询之外。 如果你想包括他,因为他买了CC产品,虽然他后来买了DE,评论,我会说明如何。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM