2012-05-08 12 views
3

Я ищу, чтобы использовать запрос LEFT JOIN для получения некоторых результатов из двух таблиц с отношением «один ко многим», но ограничить набор результатов на основе количество «детей». Я две таблицы структурированы как:Как ограничить набор результатов SQL LEFT JOIN query по счету

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

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

(Остальная часть данных в таблицах не имеет значения для этого запроса.)

Что я хотел бы сделать, это получить все идентификаторы клиентов и их идентификаторы заказов , отсортированный по клиенту, , но ограничен для клиентов, которые разместили несколько заказов. В этом примере, результаты будут выглядеть следующим образом:

cust_id order_id 
1   100 
1   102 

Я начал с базовым LEFT JOIN для пары идентификаторов заказов с их клиентом, но не может понять, как выйти из всех клиентов, которые Хейвен» t заказал не менее двух раз.

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, если вы не любите РЕГИСТРИРУЙТЕСЬ

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

Это близко ... [Ответ Конрада Фрикса] (http: // stackoverflow.com/a/10507232/1304626), кажется, дает правильный набор результатов, а ваш дает одинаковое количество строк; однако идентификаторы заказов «под» каждого идентификатора клиента дублируются. Например, вместо «1, 100; 1, 102» он дает «1, 100; 1, 100» (чтобы расширить пример в моем вопросе). –

+1

Ответ отредактирован с исправлением. SQL действительно требует попыток и настройки, так что это проблема с ответами на манжету SQL. –

+0

+1 Интересное решение. Я никогда не видел, чтобы кто-нибудь решал эту проблему, создавая [квадрат квадрата] (http://sqlfiddle.com/#!2/5ba19/3), позволяя вам подсчитывать и группировать по тому же полю. –

0

Если вы исключаете клиентов, которые не заказывали, тогда LEFT JOIN не нужно, нет?

Поскольку вы хотите получить идентификаторы заказов в результирующем наборе, сначала нужно запустить запрос 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` 
Смежные вопросы