tags:

views:

133

answers:

4

I have the following tables:

Table: user_groups (many-to-many)

  • user_id (int)
  • group_id (varchar)

Table: profile_groups (many-to-many)

  • profile_id (int)
  • group_id (varchar)

So basically, I want to write a sql script to find out what profile is assigned to each user.

So in the end there should be only 2 columns: user_id and profile_id.

How would I go about doing this?

Edit: It's actually a lot more complicated than a simple join.

E.g.

User_groups may have the following rows

  • 1 group1
  • 1 group2
  • 1 group3
  • 2 group1
  • 2 group2
  • 3 group4

and profile_groups may have the following:

  • 11 group1
  • 11 group2
  • 11 group3
  • 21 group1
  • 21 group2
  • 22 group4

So the result should be

  • 1 11
  • 2 21
  • 3 22

Each user should only have ONE profile

+2  A: 
   SELECT ug.user_id, pg.profile_id
     FROM user_groups AS ug
LEFT JOIN profile_groups AS pg
       ON ug.group_id = pg.group_id
hsz
Darn! Beat me to it.
Mike Sickler
Oh, after your edit: start query with `SELECT DISTINCT ...`
hsz
+1  A: 

This will show you a list of users who are associated to profiles:

SELECT ug.user_id,
       pg.profile_id
  FROM USER_GROUPS ug
  JOIN PROFILE_GROUPS pg ON pg.group_id = ug.group_id

...while this will return a list of all the users, who may be associated to a profile. If they are not, the profile_id column will be null:

   SELECT ug.user_id,
          pg.profile_id
     FROM USER_GROUPS ug
LEFT JOIN PROFILE_GROUPS pg ON pg.group_id = ug.group_id

Keep in mind that because of the relationships being one user_id to many profiles, the user_id will likely be displayed multiple times, and possibly duplicates. For a non duplicated list of data, add the DISTINCT clause or define the GROUP BY clause. IE:

Using DISTINCT

   SELECT DISTINCT
          ug.user_id,
          pg.profile_id
     FROM USER_GROUPS ug
LEFT JOIN PROFILE_GROUPS pg ON pg.group_id = ug.group_id

Using GROUP BY

   SELECT ug.user_id,
          pg.profile_id
     FROM USER_GROUPS ug
LEFT JOIN PROFILE_GROUPS pg ON pg.group_id = ug.group_id
 GROUP BY ug.user_id, pg.profile_id
OMG Ponies
Good JOIN resource: http://www.codinghorror.com/blog/archives/000976.html
OMG Ponies
Thanks for taking the time to write that up, I just made some edits to clarify things a little bit. It's actually a lot more complicated than a simple join query.
PCBEEF
No, it still is not. ;-)
hsz
@PCBEEF: hsz is correct - my answer covers your updated criteria.
OMG Ponies
+4  A: 

I just saw a question like this the other day. I think the hard part here is you're looking for user_id/profile_id combinations where the user_id has every group_id that the profile_id has, no more and no less. So take the usual join and add some correlation to count the number of group_ids each profile/user has and make sure they match (this has been edited a few times):

 select user_id, profile_id 
    from user_groups join profile_groups on 
    user_groups.group_id=profile_groups.group_id 
    group by user_id, profile_id
    having count(user_groups.group_id) = 
    (select count(*) from profile_groups as pg where 
    pg.profile_id=profile_groups.profile_id)
    and count(profile_groups.group_id) = (select count(*) from user_groups as ug where 
    ug.user_id=user_groups.user_id)
    ;

Here's a run which includes two profiles with three groups each, with one common group between them and a new user in the fourth profile:

sqlite>  create table user_groups (user_id integer, group_id varchar);
sqlite>  create table profile_groups (profile_id integer, group_id varchar);
sqlite>  insert into user_groups values(1, 'group1');
sqlite>  insert into user_groups values(1, 'group2');
sqlite>  insert into user_groups values(1, 'group3');
sqlite>  insert into user_groups values(2, 'group1');
sqlite>  insert into user_groups values(2, 'group2');
sqlite>  insert into user_groups values(3, 'group4');
sqlite>  insert into user_groups values(4, 'group1');
sqlite>  insert into user_groups values(4, 'group5');
sqlite>  insert into user_groups values(4, 'group6');
sqlite> 
sqlite>  insert into profile_groups values (11, 'group1');
sqlite>  insert into profile_groups values (11, 'group2');
sqlite>  insert into profile_groups values (11, 'group3');
sqlite> 
sqlite>  insert into profile_groups values (21, 'group1');
sqlite>  insert into profile_groups values (21, 'group2');
sqlite> 
sqlite>  insert into profile_groups values (22, 'group4');
sqlite> 
sqlite>  insert into profile_groups values (23, 'group1');
sqlite>  insert into profile_groups values (23, 'group5');
sqlite>  insert into profile_groups values (23, 'group6');
sqlite>  select user_id, profile_id 
   ...>     from user_groups join profile_groups on 
   ...>     user_groups.group_id=profile_groups.group_id 
   ...>     group by user_id, profile_id
   ...>     having count(user_groups.group_id) = 
   ...>     (select count(*) from profile_groups as pg where 
   ...>     pg.profile_id=profile_groups.profile_id)
   ...>     and count(profile_groups.group_id) = (select count(*) from user_groups as ug where 
   ...>     ug.user_id=user_groups.user_id)
   ...>     ;
1|11
2|21
3|22
4|23
zzzeek
Yes, this is what I'm trying to achieve. It's getting close to what I want however there is still a problem since it only checks the count rather than the actual groups. So if there are two profiles with 3 groups in each and one group is common between them, the user will come up as having two profiles.
PCBEEF
I'll edit to show my original query which is more complex but seems to address this case.
zzzeek
the count(table.group_id)'s can each be replaced with count(*), but somehow counting the "group_id" columns seems more intuitive to me.
zzzeek
That is quite ingenious! Would have took me forever to work that out. Cheers!
PCBEEF
A: 

PCBEEF, judging from the comments below zzzeek's answer, you want to use the ALL operator. BTW, your question is terribly unclear, the edit didn't help.

just somebody