2012-01-21 3 views
1

Скажем, у меня есть стол с двумя колонками: имя и настроение. Строка содержит имя человека и их настроение, если у них много настроений, тогда в БД хранится несколько строк.Как я могу выбрать данные mysql с инструкцией объединения, где данные соответствуют каждому оператору select, т. Е. Объединить оператор AND с UNION?

Например, в базе данных находится Джон, который счастлив, взволнован и горд.

Это представлено как

John Happy 
John Excited 
John Proud 

То, что я хочу сделать, это выбрать имя на основе нескольких настроений удовлетворяются. Похож на UNION:

SELECT name WHERE mood=Happy 
UNION 
SELECT name WHERE mood=Excited 
UNION 
SELECT name WHERE mood=Proud 

Однако использование вышеуказанного союза приведет к:

John 
John 
John 

Союз все приведет к одному результату одного Иоанна, но было бы также выбрать любые имена, которые соответствуют только одному запросов.

Я могу придумать несколько алгоритмов, которые будут принимать каждый отдельный ресурс mysql_result (я использую PHP), и искать соответствующие результаты, но то, что я хочу знать, заключается в том, облегчает ли MySQL это.

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

ответ

3

При условии, у вас нет дубликатов, вы можете сделать это с помощью подзапроса:

SELECT `name` FROM (
    SELECT `name`, COUNT(*) AS `count` FROM `moods` 
    WHERE `mood` IN ('Excited', 'Happy', 'Proud') GROUP BY `name` 
) WHERE `count` = 3 

В качестве альтернативы, вы можете использовать присоединиться:

SELECT `m1`.`name` FROM `moods` `m1` 
JOIN `moods` `m2` USING (`name`) 
JOIN `moods` `m3` USING (`name`) 
WHERE `m1`.`mood` = 'Excited' AND `m2`.`mood` = 'Happy' AND `m3`.`mood` = 'Proud' 

Не так мило, но может быть быстрее, если вы используете LIMIT. А может и нет. Зависит от планировщика запросов.

UPD: благодаря Tudor Constantin за напоминание о том, первый запрос может затем быть:

SELECT `name` FROM `moods` 
WHERE `mood` IN ('Excited', 'Happy', 'Proud') 
GROUP BY `name` 
HAVING COUNT(*)>3 
+0

Спасибо, я использовал первый, он работает совершенно отлично, я проверяю CRON на дубликаты каждую ночь, поэтому не беспокойтесь. Что касается обновления, он не возвращает никаких результатов, какая разница должна быть сделана? Спасибо большое. – Sam

+0

Логика с HAVING практически такая же, не знаю, есть ли какая-либо разница в производительности. –

1

Если я правильно понял ваш вопрос, я думаю, что в этом случае вам действительно не нужен UNION, а просто несколько условий в заявлении WHERE.

Попробуйте это:

SELECT name, mood FROM myTable WHERE mood in ('Happy','Excited','Proud') 

Этот должен дать результат:

John, Happy 
John, Excited 
John, Proud 

Если вы не заботитесь о получении нескольких результатов для настроения, попробуйте это:

SELECT DISTINCT name FROM myTable WHERE mood in ('Happy','Excited','Proud') 

Который только что даст:

Этот должен дать результат:

John 

Обновлено Если вы хотите, чтобы соответствовать все условия, вы, вероятно, придется использовать подзапросы:

SELECT DISTINCT name FROM myTable 
WHERE name IN 
    (SELECT name FROM myTable WHERE mood = 'Happy') 
AND name IN 
    (SELECT name FROM myTable WHERE mood = 'Excited') 
AND name IN 
    (SELECT name FROM myTable WHERE mood = 'Proud') 
+0

Пол, спасибо за ваш ответ, очень ценный. Использование SELECT DISTINCT, похоже, не приносит никаких результатов, поскольку ваше первое решение действительно дает все результаты. – Sam

+0

Не возвращает ли это все имена, где по крайней мере одно настроение соответствует (не все три)? –

+0

Просто попробовал еще раз, на самом деле использование DISTINCT приносит результаты, но они не соответствуют каждому условию, то есть возвращаются другие люди, которые просто счастливы. Можно ли как-то применить оператор И к вашему решению? – Sam

0

Заменить UNION с INTERSECT.

+0

нет 'INTERSECT' в MySQL –

+0

это будет работать (в SQL с' INTERSECT'), но кажется неэффективным, по существу, используя 3 выбора для достижения того, что * можно * сделать с помощью одного? –

1

Попробуйте с:

SELECT name FROM user_moods um1 
    INNER JOIN user_moods um2 ON um1.name = um2.name 
WHERE um1.mood IN ('Happy','Excited','Proud') 
GROUP BY um2.mood 
HAVING COUNT(um2.mood) = 3 # the number of different moods 
+0

Хорошо, я забыл о HAVING, но почему добавочное соединение? Кроме того, в руководстве MySQL указано, что «например, предложение HAVING должно появиться после любого предложения GROUP BY и перед любым предложением ORDER BY». –

1

ваш запрос уже правильно. вы можете указать ADD дополнительный столбец, в котором вы искали слово в предложении WHERE.

SELECT name,'Happy' as imood WHERE mood='Happy' 
    UNION 
SELECT name,'Excited' as imood WHERE mood='Excited' 
    UNION 
SELECT name,'Proud' as imood WHERE mood='Proud' 
+0

Спасибо большое за ваш ответ, очень ценится. Проблема в том, что это возвращает имена людей, которые просто выполняют одно из выбранных утверждений, а не все из них. – Sam