tags:

views:

90

answers:

4
+3  Q: 

joining two tables

I have users table. There are three other tables: developers, managers, testers. All of these tables have a foreign key user_id.

I need to find all the users who are either developer or manager. What the sql will look like?

Update: Someone can be both a developer and a manager.

+7  A: 

One way to do it would be

SELECT  u.*, 'Developer'
FROM    users u
        INNER JOIN developer d ON d.user_id = u.user_id
UNION ALL 
SELECT  u.*, 'Manager'
FROM    users u
        INNER JOIN manager m ON m.user_id = u.user_id
Lieven
A: 
SELECT
    user_id
     /* ...other desired columns from the user table... */
FROM
    user
WHERE
    user_id IN (SELECT user_id FROM developer UNION SELECT user_id FROM manager)

Here I am using IN rather than EXISTS so that the developer and manager tables only need to be queried one time. It's possible that the optimizer may do this anyway, but this makes it explicit.

Also, this solution does not return duplicates for users who are both managers and developers.

Jeffrey L Whitledge
I'd use UNION ALL in this case...you are now unnecessarily de-deduplicating the subquery result due to UNION
Roland Bouman
@Roland: the engines will take care of it automatically. Even `MySQL` is smart enough to ignore `DISTINCT` in the `IN` predicate.
Quassnoi
@Roland Bouman - I was wondering where all this reflexive UNION ALL was coming from. So it's a performance thing. I don't think I'm going to switch, because the UNION statement is the one place in all of the SQL language where the functionality actually matches Relational Database Theory!
Jeffrey L Whitledge
@Jeffrey: I think what Quassnoi means is that in your solution, it doesn't make a difference. The other solutions do benefit from a union all performance wise.
Lieven
@Quassnoi: thanks, didn't know that. That said, my SQL is habitual. If I don't need UNION, it's gonna be UNION ALL forevah evah :)
Roland Bouman
@Roland: if you look into my answer, you'll see the same :) I just wanted to say it doesn't really matter.
Quassnoi
I know this isn't a popular opinion, but SELECT's ability to return duplicate rows is a bug (one of many) in the design of SQL. UNION's default behavior gets it right. UNION ALL is a way to tell SQL to just "do it wrong, as usual". Whether the query decides that dupe elimination is necessary, because of what it knows about the unique constraints on the source tables or the queries themselves, and how it eliminates dupes--existing indexes, implicitly building indexes, or doing table-scans, etc.--are irrelivant implementation details. Describing what you want, not how to get it, is the goal.
Jeffrey L Whitledge
Jeffrey, I don't think you can generically say that implementation details are irrelevant. They are not when you suffer from them.
Roland Bouman
@Jeffrey: It is often said that SQL is set-based, but strictly speaking, it's not. SQL was designed to be able to work with multisets (bags), not only with sets. Limiting it to only set operations would complicate many real-world tasks.
Quassnoi
@Quassnoi - Yes, with SQL we can get a list of all the things that Steve Martin needs: this lamp, and this tennis racket, and this lamp, and this ash tray, and this lamp, and this tennis racket, and this ash tray, and this lamp... :-P
Jeffrey L Whitledge
@Jeffrey: exactly.
Quassnoi
+2  A: 
SELECT  *
FROM    users u
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    developers
        WHERE   user_id = u.id
        UNION ALL
        SELECT  NULL
        FROM    managers
        WHERE   user_id = u.id
        )
Quassnoi
Quassnoi - good! but you have a typo - users needs a u alias.
Roland Bouman
@Roland: we really need an embedded query parser on SO!
Quassnoi
+1  A: 
SELECT    u.*, 
          CASE d.user_id IS NULL THEN 'N' ELSE 'Y' END is_developer,
          CASE m.user_id IS NULL THEN 'N' ELSE 'Y' END is_manager
FROM      users u                -- all users
LEFT JOIN developers d           -- perhaps a developer
ON        u.user_id = d.user_id
LEFT JOIN manager m              -- perhaps a manager
ON        u.user_id = m.user_id
WHERE     d.user_id IS NOT NULL  -- either a developer
   OR     m.user_id IS NOT NULL  -- or a manager (or both)
Roland Bouman