2012-05-08 15 views
3

我正在寻找使用LEFT JOIN查询从一对多关系的两个表获取一些结果,但限制基于计数“孩子”。我有两个表结构类似:如何通过计数限制SQL 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` 

谢谢大家。

回答

7

一种方法是创建一个内联视图来获取具有多个订单的客户以及内部联接。你也可以做一个IN或EXISTS,如果你不喜欢JOIN

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

在我说出来之前先给我答案! –

+0

谢谢!这似乎是给我我正在寻找的结果集。 –

+0

很高兴我能提供帮助,但你应该注意到,马林皮尔斯是正确的,因为我们已经排除了没有任何订单的客户,所以'LEFT JOIN'没有做任何事情。 –

1

首先,你不会需要加入到留外,因为和内部之间的唯一区别加盟将包括没有订单的客户,因为他们的订单少于两个,所以您不需要这些订单。

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

接近...... [Conrad Frix的回答](http:// stackoverflow。com/a/10507232/1304626)似乎给出了正确的结果集,并且你给出了相同的行数;但是,每个客户ID下面的订单ID都是重复的。例如,而不是“1,100; 1,102”,它会给出“1,100; 1,100”(以扩展我的问题中的示例)。用修正编辑的 –

+1

答案。 SQL真的需要尝试和调整,所以这是关于袖扣SQL答案的问题。 –

+0

+1有趣的解决方案。我从来没有见过任何人通过创建一个[笛卡尔正方形](http://sqlfiddle.com/#!2/5ba19/3)来解决此问题,从而允许您通过同一字段进行计数和分组。 –

0

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

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

在SQL Server中,2005+,热膨胀系数会做的伎俩为计数查询,然后将结果设定您想要可以基于数查询产生:

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` 

让我知道如果您有任何疑问

+0

这是针对MySQL的,所以我不能评论第一个建议会奏效。但是,第二个建议似乎将mysqld进程发送到无限循环。这个查询对我来说似乎很合理,所以这可能是MySQL本身的一个问题。最近他们的版本越来越变得越来越笨重 –

1

嘿,我猜我有点慢,但我会发布我的答案。它略有不同,但仍然有效。

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

对于其他答案的替代方法,您可以使用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`