【问题标题】:Select all customers except if they have another product - SQL选择所有客户,除非他们有其他产品 - SQL
【发布时间】:2016-03-29 19:07:58
【问题描述】:

我有两张桌子。一个由客户组成,另一个由他们购买的产品组成:

表客户

CustID, Name
  1,     Tom 
  2,     Lisa 
  3,     Fred

餐桌产品

CustID, Item
  1,     Toaster
  1,     Breadbox
  2,     Toaster
  3,     Toaster

我想吸引所有购买了烤面包机的顾客,除非他们也购买了面包盒。

所以我尝试了以下方法:

SELECT * FROM Customer
JOIN Product
    ON Customer.CustID=Product.CustID
WHERE Product in
    (SELECT 
        Item
    FROM Product
    WHERE (Item = 'Toaster' AND Item != 'Breadbox'));

还有:

SELECT * FROM Customer
INNER Join Product
ON Customer.CustID=PRODUCT.CustID
WHERE Product.Item = 'Toaster'
AND Product.Item NOT IN ('Breadbox');

但两者都给出了相同的结果,其中包括汤姆,他已经拥有一个面包盒。

我如何确保只有拥有烤面包机但不拥有面包盒的客户才会被列出?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:
    SELECT * FROM Customer C
    LEFT JOIN Product PT ON C.CustID = PT.CustID AND PT.Item = 'Toaster'
    LEFT JOIN Product PB ON C.CustID = PB.CustID AND PB.Item = 'Breadbox'
    WHERE PT.Item IS NOT NULL AND PB.Item IS NULL
    

    【讨论】:

      【解决方案2】:

      这是我的第一篇文章,请原谅任何失误。 Customer 和 Product 表之间存在“多对一”关系。要进行要应用的逻辑限制,您需要聚合 Product 表或连接 Product 表两次。实际上,您正在寻求将多对一关系分解为“一对一”关系。

      以下是 Product 表连接两次的一些示例。

      SELECT DISTINCT
      a.Name
      FROM
      Customer a
      JOIN Product b ON a.CustID = b.CustID
      LEFT JOIN Product c on a.CustID = c.CustID AND c.Item = 'Breadbox'
      WHERE
      b.Item = 'Toaster' AND
      c.CustID IS NULL
      

      或(根据索引,效率略低)

      SELECT DISTINCT
      a.Name
      FROM
      Customer a
      JOIN Product b ON a.CustID = b.CustID
      WHERE
      b.Item = 'Toaster' AND
      NOT EXISTS (SELECT 1 FROM Product c where a.CustID = c.CustID AND c.Item = 'Breadbox')
      

      而且,这里是一个连接 Product 表的示例 - 可能比您需要的更复杂。

      SELECT
      a.Name
      FROM
      Customer a
      JOIN
      (
          SELECT 
          CustID, 
          SUM(case when Item = 'Toaster' then 1 else 0 end) sum_Toaster,
          SUM(case when Item = 'Breadbox' then 1 else 0 end) sum_Breadbox
          FROM
          Product
          WHERE 
          Item in ('Toaster','Breadbox')
          GROUP BY
          CustID
          HAVING
          SUM(case when Item = 'Toaster' then 1 else 0 end) > 0 AND
          SUM(case when Item = 'Breadbox' then 1 else 0 end) = 0
      ) b ON a.CustID = b.CustID
      

      【讨论】:

        【解决方案3】:
        SELECT distinct * FROM Customer
         LEFT JOIN Product ON Customer.CustID=Product.CustID
        WHERE Item = 'Toaster'
        AND Customer.CustID NOT IN (
        Select CustID FROM Product Where Item = 'Breadbox'
        )
        

        【讨论】:

        • 如果可能的话,这个查询将返回根本没有产品的客户,所以在我看来你想要一个内部连接。如果可能有多个烤面包机,这也会多次列出一个客户。
        • 我试过查询,它工作正常,你能举个例子吗? @shawnt00
        • 我的错。我误读了where 作为连接条件的一部分。但是你真的不妨写inner join,因为这就是你会得到的。
        • 您对第二个问题(多条记录)是对的,我添加distinct 来解决这个问题,谢谢@shawnt00
        【解决方案4】:

        试试这个:

        SELECT c.CustID, c.Name
        FROM customer AS c
        JOIN product AS p ON c.CustID = p.CustID
        GROUP BY c.CustID, c.Name
        HAVING SUM(p.Item = 'Toaster') >= 1 AND SUM(p.Item = 'Breadbox') = 0
        

        【讨论】:

          【解决方案5】:
          select c.CustID, min(c.Name) as Name
          from Customer c inner join Product p
              on p.CustID = c.CustID
          where p.Item in ('Toaster', 'Breadbox')
          group by c.CustID
          having
              max(p.Item) = 'Toaster' and min(p.Item) = 'Toaster'
          

          having
                  count(case when p.Item = 'Toaster'  then 1 end) > 0
              and count(case when p.Item = 'Breadbox' then 1 end) = 0
          

          对于第二种情况,您并不严格需要 where,尽管它可能有助于大型表的性能。

          【讨论】:

            猜你喜欢
            • 2010-11-26
            • 2020-06-06
            • 1970-01-01
            • 1970-01-01
            • 2019-01-08
            • 2020-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多