【问题标题】:How to limit result set of an SQL LEFT JOIN query by count如何按计数限制 SQL LEFT JOIN 查询的结果集
【发布时间】:2012-05-08 22:02:42
【问题描述】:

我希望使用 LEFT JOIN 查询从具有一对多关系的两个表中获取一些结果,但根据“孩子”的数量限制结果集。我有两个表结构如下:

customers
id    name    ...
1     "bob"   ...
2     "jill"  ...

orders
id    customer_id    ...
100   1              ...
101   2              ...
102   1              ...

(表中的其余数据与此查询无关。)

我想做的是获取所有客户 ID 及其订单 ID,按客户排序,但仅限于下过多个订单的客户。在此示例中,结果将看起来像:

cust_id    order_id
1          100
1          102

我已经开始使用基本的 LEFT JOIN 来将订单 ID 与他们的客户配对,但不知道如何排除所有未订购至少两次的客户。

SELECT 
    `customers`.`id` AS `cust_id`,
    `orders`.`id` AS `order_id`
FROM
    `customers`
LEFT JOIN `orders` ON
    `customers`.`id` = `orders`.`customer_id`
ORDER BY
    `cust_id`

谢谢大家。

【问题讨论】:

    标签: mysql sql join


    【解决方案1】:

    一种方法是创建一个内联视图,以获取拥有多个订单的客户及其内部连接。如果您不喜欢 JOIN,您也可以执行 IN 或 EXISTS

    SELECT 
        `customers`.`id` AS `cust_id`,
        `orders`.`id` AS `order_id`
    FROM
        `customers`
    LEFT JOIN `orders` ON
        `customers`.`id` = `orders`.`customer_id`
    INNER JOIN 
          (SELECT `customer_id `    
           FROM `orders`
           GROUP BY `customer_id`    
           HAVING COUNT(id) > 1) as `morethanone`
    On
        `customer`.`id`  = `morethanone`.`custmor_id`
    ORDER BY
        `cust_id`
    

    【讨论】:

    • 在我说之前先把答案拿走!
    • 谢谢!这似乎给了我正在寻找的结果集。
    • 很高兴我能提供帮助,但您应该注意,Marlin Pierce 是正确的,LEFT JOIN 并没有真正做任何事情,因为我们已经淘汰了任何没有订单的客户。跨度>
    【解决方案2】:

    嘿,我想我有点慢,但无论如何我都会发布我的答案。它略有不同,但仍然有效。

    SELECT `customers`.`id` AS `cust_id` , count( orders.id ) AS count_orders
    FROM `customers`
    JOIN `orders` ON `customers`.`id` = `orders`.`customer_id`
    GROUP BY customers.id
    HAVING count( orders.id ) >1
    ORDER BY `cust_id`
    

    【讨论】:

      【解决方案3】:

      首先,您不需要将联接保留在外部,因为它与内部联接之间的唯一区别是包括没有订单的客户,并且您不需要在结果中使用他们,因为他们的订单较少超过两个订单。

      SELECT customers.id AS `cust_id`, orders.id AS `order_id`
      FROM customers
           INNER JOIN orders ON `customers`.`id` = `orders`.`customer_id`
           INNER JOIN orders count_orders ON customers.id = count_orders.customer_id
      GROUP BY count_orders.id, orders.id
      HAVING count(count_orders.id) >= 2
      ORDER BY `cust_id`
      

      【讨论】:

      • 这很接近...Conrad Frix's answer 似乎给出了正确的结果集,而你的给出了相同的行数;但是,每个客户 ID“下”的订单 ID 是重复的。例如,它给出的不是“1, 100; 1, 102”,而是“1, 100; 1, 100”(扩展我的问题中的示例)。
      • 已使用修复程序编辑答案。 SQL 确实需要尝试和调整,所以这就是即兴 SQL 答案的问题。
      • +1 有趣的解决方案。我从未见过有人通过创建cartesian square 来解决此问题,允许您按相同字段进行计数和分组
      • 在 FROM 子句中多次连接一个表是一种常见的 SQL 技术。
      • @MarlinPierce 嗯加入了table 多个times 是的。这样做是为了创建一个笛卡尔积,以便您可以分组和计数......我不记得看到过(并且这个特定问题的变体出现了很多)
      【解决方案4】:

      如果您排除了尚未订购的客户,那么 LEFT JOIN 是不必要的,不是吗?

      由于您需要结果集中的订单 ID,因此需要首先运行 COUNT 查询。

      在 SQL Server 2005+ 中,CTE 将完成计数查询,然后可以根据该计数查询生成您想要的结果集:

      WITH customerWithMoreThanOneOrder AS
      (
          SELECT 
              `customers`.`id` AS `cust_id`
          FROM
              `customers`
          INNER JOIN `orders` ON
              `customers`.`id` = `orders`.`customer_id`
          GROUP BY 
              `customers`.`id`
          HAVING COUNT(0) > 1
      )
      
      SELECT 
          `customers`.`id` AS `cust_id`,
          `orders`.`id` AS `order_id`
      FROM
          `customers`
      INNER JOIN `orders` ON
          `customers`.`id` = `orders`.`customer_id`
      WHERE `customers`.`id` IN (SELECT cust_id FROM customerWithMoreThanOneOrder)
      ORDER BY
          `cust_id`
      

      如果您使用的数据库不支持这种结构,那么只需将计数查询放在 IN 子查询的括号中,如下所示:

      SELECT 
          `customers`.`id` AS `cust_id`,
          `orders`.`id` AS `order_id`
      FROM
          `customers`
      INNER JOIN `orders` ON
          `customers`.`id` = `orders`.`customer_id`
      WHERE `customers`.`id` IN (SELECT 
                                     `customers`.`id` AS `cust_id`
                                 FROM
                                     `customers`
                                 INNER JOIN `orders` ON
                                     `customers`.`id` = `orders`.`customer_id`
                                 GROUP BY 
                                     `customers`.`id`
                                 HAVING COUNT(0) > 1)
      ORDER BY
          `cust_id`
      

      如果您有任何问题,请告诉我

      【讨论】:

      • 这是针对 MySQL 的,所以我无法评论第一个建议是否可行。但是,第二个建议似乎将 mysqld 进程发送到无限循环。这个查询对我来说似乎是合乎逻辑的,所以它可能是 MySQL 本身的问题。他们的版本最近越来越错误......
      【解决方案5】:

      其他答案的替代方案,您可以使用 IN 子句。

      SELECT 
          `customers`.`id` AS `cust_id`,
          `orders`.`id` AS `order_id`
      FROM
          `customers`
      LEFT JOIN `orders` ON
          `customers`.`id` = `orders`.`customer_id`
      WHERE `customer_id` IN (SELECT `customer_id` FROM `orders` GROUP BY `customer_id` HAVING COUNT(*) > 1)
      ORDER BY
          `cust_id`
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-19
        • 1970-01-01
        • 2011-03-23
        • 2016-09-10
        • 2015-01-10
        • 2011-03-08
        • 2015-02-24
        • 1970-01-01
        相关资源
        最近更新 更多