2012-05-07 3 views
2

У меня есть следующий SQL:SQL вернуть слит набор результатов

SELECT `table1`.`value`, `table2`.* 
FROM `table2` 
INNER JOIN `table1` ON `table2`.`product_id` = `table1`.`entity_id` 
WHERE `table2`.`created_at` > '2012-04-23' and 
(`table1`.`value` = 264 OR `table1`.`value` = 260) 
order by order_id 

который возвращает набор результатов, как это (Это только часть возвращенных результатов):

value order_id ... 
260 1234 
260 1235 
260 1236 
264 1236 
260 1237 
260 1238 
260 1239 
264 1239 
264 1240 
260 1241 

Я хочу получить запрос, который будет принимать эти результаты и только возвращать заказы, где order_id содержит как значение 260, так и 264. Исходя из этого примера, конечный результат, который я ищу, -

260 1236 
264 1236 
260 1239 
264 1239 

Я думал, что это можно сделать с помощью подмножества, но я не совсем уверен в деталях, чтобы выполнить его.

+0

У меня трудно понять это. Можете ли вы создать SQLfiddle с некоторыми тестовыми данными? – Hawkee

+0

вам нужны как 'value', так и' order_id' или просто список 'order_id', которые имеют значение 260 и 264?первый случай уже ответил, последний - это простое самосоединение (это будет намного быстрее). – Aprillion

+0

@deathApril Хороший вопрос о самосоединении, с оговоркой, что будет сложнее расширить, когда список вырастет до 3 'order_id's ... then 4, 5 .... –

ответ

5

Это может быть достигнуто с relational division:

select r.order_id from (
    select 
    dividend.* 
    from your_table_or_query as dividend -- assumes no duplicates in `dividend`; use `distinct` if there are any 
    inner join divisor 
    on dividend.value = divisor.value 
) as r 
group by r.order_id 
having count(*) = (select count(*) from divisor); 

результат:

+----------+ 
| order_id | 
+----------+ 
|  1236 | 
|  1239 | 
+----------+ 
2 rows in set (0.00 sec) 

где ваш запрос your_table_or_query и

select 260 as value from dual union select 264 as value from dual 

является divisor.

Это вернет идентификаторы 1236 и 1239 заказа; они могут тогда быть join ed в исходный запрос, чтобы получить все строки с этими идентификаторами заказа, если это то, что вы хотите.


Полный запрос вместе с операторами вставки:

create table divisor (value int); 
insert into divisor values (260), (264); 

create table your_table_or_query (value int, order_id int); 
insert into your_table_or_query values (260, 1234), (260, 1235), (260, 1236), (264, 1236), (260, 1237), (260, 1238), (260, 1239), (264, 1239), (264, 1240), (260, 1241); 


select y.* from (
    select r.order_id from (
    select 
     dividend.* 
    from your_table_or_query as dividend 
    inner join divisor 
     on dividend.value = divisor.value 
) as r 
    group by r.order_id 
    having count(*) = (select count(*) from divisor) 
) as quotient 
inner join your_table_or_query y 
    on quotient.order_id = y.order_id; 

Результат:

+-------+----------+ 
| value | order_id | 
+-------+----------+ 
| 260 |  1236 | 
| 264 |  1236 | 
| 260 |  1239 | 
| 264 |  1239 | 
+-------+----------+ 
4 rows in set (0.00 sec) 
+0

+1 большое универсальное решение, но в этом конкретном случае я считаю, что это слишком дорого, используя 'has' вместо простого соединения. – Aprillion

+0

Насколько это дорого, зависит в основном от контекста: размер ввода, размер выходного сигнала и т. д. –

+0

Это заняло у меня некоторое время, чтобы обернуть голову вокруг того, что должен быть «дивизор», но в итоге я добрался туда. Благодаря! –

-1
SELECT `table1`.`value`, `table2`.* 
FROM `table1` 
LEFT JOIN `table2` ON `table1`.`entity_id` = `table2`.`product_id` 
WHERE 
(`table1`.`value` = 264 OR `table1`.`value` = 260) 
AND `table2`.`created_at` > '2012-04-23' 
ORDER BY `table2`.order_id 

Выравнивание по левому краю, чтобы она соответствовала только результаты table1.value со спичками и оставить информацию из другой таблицы из

+0

Я считаю, что 'LEFT JOIN' будет делать как раз наоборот. – bfavaretto

+0

Возможно, я неправильно понял вопрос, а затем – Scarecrow

+0

Ваш ответ, похоже, в порядке, вам нужно то, что вы добавили в 'WHERE'. Ваш 'LEFT JOIN' будет вести себя как' INNER JOIN', потому что 'WHERE' содержит условие на' table2'. – bfavaretto

1

Как насчет этого?

SELECT table1.value, table2.* 
FROM table2 
INNER JOIN table1 
ON table2.product_id = table1.entity_id 
WHERE table2.created_at > '2012-04-23' AND 
(table1.value = 264 OR table1.value = 260) 
AND table2.order_id IN (
    SELECT table2.order_id 
    FROM table2 
    INNER JOIN table1 
    ON table2.product_id = table1.entity_id 
    WHERE table2.created_at > '2012-04-23' AND 
    (table1.value = 264 OR table1.value = 260) 
    GROUP BY table2.order_id 
    HAVING COUNT(*) = 2 
) 

(извините за опуская апострофа, я не в курсе, какие MySQL требования в этой области, этот синтаксис MS-SQL совместимые)

+1

Я начал с этого, но время, которое нужно выполнить на сервере, было слишком много для его переноса, и мне пришлось остановить процесс. Это может быть жизнеспособным решением, но не одним из 4 600 записей. –

1

это будет возвращать список заказов, которые имеют оба значение 260 и 264 - если кому-то нужно именно это вместо дублированных результатов для каждого из значений:

SELECT `table2`.* 
FROM `table2` 
INNER JOIN `table1` as `table1_264` 
    ON `table2`.`product_id` = `table1_264`.`entity_id` 
    AND `table1_264`.`value` = 264 
INNER JOIN `table1` as `table1_260` 
    ON `table2`.`product_id` = `table1_260`.`entity_id` 
    AND `table1_260`.`value` = 260 
WHERE `table2`.`created_at` > '2012-04-23' 
order by order_id 


или если кто-то хочет более быстрое решение без дорогостоящих having пунктов (+, конечно, вы можете сохранить запрос или использовать КТР вместо того, чтобы просто повторять его)

SELECT 264 as `value`, `table2`.* 
FROM `table2` 
INNER JOIN `table1` as `table1_264` ON `table2`.`product_id` = `table1_264`.`entity_id` AND `table1_264`.`value` = 264 
INNER JOIN `table1` as `table1_260` ON `table2`.`product_id` = `table1_260`.`entity_id` AND `table1_260`.`value` = 260 
WHERE `table2`.`created_at` > '2012-04-23' 
UNION ALL 
SELECT 260, `table2`.* 
FROM `table2` 
INNER JOIN `table1` as `table1_264` ON `table2`.`product_id` = `table1_264`.`entity_id` AND `table1_264`.`value` = 264 
INNER JOIN `table1` as `table1_260` ON `table2`.`product_id` = `table1_260`.`entity_id` AND `table1_260`.`value` = 260 
WHERE `table2`.`created_at` > '2012-04-23' 
order by order_id 
+0

По какой-то причине, когда я побежал, я получаю нулевые результаты. Удаление одного из внутренних соединений обеспечило бы мне правильное количество подпунктов, и логика была бы звуковой, поэтому я поддержал ее как возможное решение для кого-то другого. Во всех аспектах это должно работать, но я перешел к другому решению, поскольку у меня были варианты. –

Смежные вопросы