How can I select mysql data with a union statement where the data matches each select statement, i.e. combine the AND operator with UNION?

StackOverflow https://stackoverflow.com/questions/8952425

Question

Lets say I have a table with just two columns: name and mood. A row holds a persons name, and their mood, if they have multiple moods, then multiple rows are stored in the DB.

For example, in the database is John, who is happy, excited, and proud.

This is represented as

John Happy
John Excited
John Proud

What I want to do is select the name based on several moods being met. Similiar to the UNION:

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

However using the above union would result in:

John
John
John

Union all would result in one single result of John, but it would also select any names that only match one of the queries.

I can think of a few algorithms which would take each individual mysql_result resource (I'm using PHP), and look for matching results, but what I want to know is whether MySQL already facilitates this.

I realise the above is quite a vague generalisation, needless to say my actual program is alot more complicated and I've dumbed it down a little for this question, please don't hesitate to ask questions.

Was it helpful?

Solution

Provided you have no duplicates, you can do it with a subquery:

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

Alternatively, you can use join:

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'

Not so cute, but might be faster if you use LIMIT. Or maybe not. Depends a lot on query planner.

UPD: thanks to Tudor Constantin for reminding me about HAVING, the first query can then be:

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

OTHER TIPS

Replace UNION with INTERSECT .

your query is already correct. you can ADD an extra column using you searched word in the WHERE clause.

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'

If I understand your question correctly, I think in this case you don't actually need a UNION but just multiple conditions in a WHERE statement.

Try this:

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

This should give the result:

John, Happy
John, Excited
John, Proud

If you don't care about getting multiple results for mood, try this:

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

Which will just give:

This should give the result:

John

Updated If you want to match ALL the conditions, you'd probably have to use subselects:

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')

Try with:

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top