tags:

views:

620

answers:

6

Thanks for the great answers!

For More Information


This is hard to explain, so lets set the stage...

userActions         userGroupMap
+------+--------+   +------+-------+
| user | action |   | user | group |
+------+--------+   +------+-------+
| x    | acted! |   | x    | a     |
| y    | acted! |   | y    | a     |
| y    | acted! |   | z    | b     |
| z    | acted! |   +------+-------+
| y    | acted! |
| z    | acted! |
| x    | acted! |
| z    | acted! |
+------+--------+

I want to select group a's actions. My idea was to

SELECT actions, user FROM userActions
    WHERE user = (SELECT user, group FROM userGroupMap WHERE group = a)

But obviously this subquery returns more than one row. Should I use a JOIN?

Subquery returns more than 1 row
A: 
SELECT actions, user FROM userActions
    WHERE user = (SELECT user FROM userGroupMap WHERE group = a)

The subquery was returning user and group (two fields) when it should be returning just user.

qpingu
I agree that the sub-query was wrong in part because of the multiple columns; however, the question was about it returning more than one row, and your version still does that - and therefore fails at runtime.
Jonathan Leffler
+1  A: 
SELECT actions, user FROM userActions
    WHERE user IN (SELECT user FROM userGroupMap WHERE group = a)

SELECT actions, user FROM userActions
    WHERE user = ANY (SELECT user FROM userGroupMap WHERE group = a)

(Amended: only the user column should be returned, as noted by others.)

Jonathan Leffler
+1  A: 

Couldn't you just do something like:

SELECT 
  a.actions, 
  a.user 
FROM 
  userActions a 
  INNER JOIN userGroupMap g 
    ON a.user = g.user
WHERE
  g.group = 'a'
snnkmtt
Yes; this works best in this situation. But there is also the issue of 'how to deal with sub-queries that return multiple rows', and that is done with IN or = ANY or variants thereof. But those queries can often be rewritten with a join instead of a sub-query.
Jonathan Leffler
+1  A: 

Actually, this query will give you what you need:

SELECT actions, user 
FROM userActions 
WHERE user IN 
    (SELECT user FROM userGroupMap WHERE group = 'a')
Nathan DeWitt
A: 

Rather use join than subquery:

SELECT
    userActions.action,
    userActions.user
FROM
    userActions
CROSS JOIN userGroupMap ON 
    userGroupMap.user = userActions.user AND
    userGroupMap.group = 'a'
glavić
On large tables, this will dramatically increase the size of the temporary table before cutting it down with group. Its less efficient than joining on a subset of data.
achinda99
What if put where statment in join ? Will that be better ?
glavić
No need for CROSS JOIN; use INNER JOIN (or just plain JOIN).
Jonathan Leffler
In MySQL, CROSS JOIN is a syntactic equivalent to INNER JOIN (they can replace each other). In standard SQL, they are not equivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used otherwise.
glavić
+1  A: 

One approach is this:

SELECT actions,
       user
FROM   userActions
WHERE  user IN
               (SELECT user
               FROM    userGroupMap
               WHERE   [group] = 'a'
               );

However, with large tables, this query tends to be inefficient and doing a join is better:

SELECT actions,
       userActions.user
FROM   userActions
       INNER JOIN
              (SELECT user
              FROM    userGroupMap
              WHERE   [group] = 'a'
              ) AS tmp
       ON     userActions.user = tmp.user;

Alternatively, as Jonathon mentioned, you could have done this and its pretty much as efficient, if not more:

SELECT actions,
       userActions.user
FROM   userActions
       INNER JOIN userGroupMap
       ON     userActions.user = userGroupMap.user
WHERE  [group] = 'a';
achinda99
Thank you! With your answer I got my results flawlessly. I also appreciate the note about large tables (Which is why I accepted your answer).Can you elaborate on why you put group in brackets-"[group]"?
Blaine
There is no obvious reason why this needs a sub-query; a straight inner-join with filtering WHERE clause should also do the job.
Jonathan Leffler
@Blaine: I put [group] in brackets because its a keyword and some DBMS freak out if keywords used as column/table names is not explicitly stated. Same reason I'd put [table] in brackets.@Jonathan Leffler: You are right, I think I was just distracted by the question and it using subqueries.
achinda99
Thanks again, this is a very helpful answer!
Blaine