How to join on conditional tables - mysql

I have to maintain a database that has 3 different tables for their users (for different roles). Unfortunately, merging them is not allowed.
There is another table that logs their activity, and this table has two columns for identifying a specific user, one is userId, and the other is roleId. Now, when I want to list user activities for all users, then depending on the value in roleId, I would have to join each row with a different table.
If there was only one table with users, the query would be something like:
SELECT * FROM activity JOIN buyers ON activity.userId = buyers.id
So how would I expand on this query now, if I had 3 tables with users: buyers, sellers, and administrators; knowing that the roleId column in the activity table identifies either a buyer, a seller, or an administrator?

SELECT *, 'Buyer' as accountType FROM activity JOIN buyers b ON activity.userId = b.id
UNION
SELECT *, 'Seller' FROM activity JOIN sellers s ON activity.userId = s.id
UNION
SELECT *, 'Admin' FROM activity JOIN administrators a ON activity.userId = a.id
may consider writing the above as a view that way I could build on it as needed, given I can't change any existing table design.
may have to spell out specific table columns as well if buyer, seller, and admin have different columns. Given you've not provided the table structures, I'm assuming they are identical for this example purpose.

Just guessing here as to how roleId relates to the other tables.
SELECT * FROM activity JOIN buyers ON activity.userId = buyers.id
WHERE activity.roleId = 1
UNION SELECT * FROM activity JOIN sellers ON activity.userId = sellers.id
WHERE activity.roleId = 2
UNION SELECT * FROM activity JOIN administrators ON activity.userId = administrators.id
WHERE activity.roleId = 3

Related

Combine two mysql tables with companies and contacts

i have two tables in mysql. The first one holds companies and the second one holds contacts that work for these companies.
There are companies without contacts, and there are several contacts that can work for one company, but there are never contacts without a company.
The tables look like this:
company table
company_id
company_name
company_telephone
contacts table
contact_id
works_for_company_id
contact_fullname
contact_telephone
I am trying to combine both tables with one select statement in order to create a list of telephone numbers for each and every entry, e. g. one company with two contacts results in three entries, each with the company name and telephone number in one row.
I tried JOIN statements, which all resulted in displaying the contacts but not the companies behind it, i tried UNION (didn't work because of different column names). What else am I missing? Any help would be appreciated.
You combine both join and union - but you will have to rename the differently named columns (via AS):
SELECT company_id, company_telephone AS phone FROM company
UNION
SELECT company_id, contact_telephone AS phone FROM company JOIN contacts ON ...
All you need is direct straight join to get all the details. You can replace * with relevant column names:
SELECT *
FROM CONTACTS_TABLE con
JOIN COMPANY_TABLE cta ON cta.company_id = con.works_for_company_id
As people told you in previous comments, you need a join/inner join
SELECT comp.company_id, cont.contact_fullname
FROM company comp
INNER JOIN contacts cont ON comp.company_id = cont.works_for_company_id;
There are companies without contacts SO you need to use LEFT JOIN
SELECT com.company_name,com.telephone ,com.company_id, con.contact_fullname
FROM company com
LEFT JOIN contacts con ON com.company_id = con.works_for_company_id;
The UNION operator is used to combine the result-set of two or more SELECT statements.
Each SELECT statement within UNION must have the same number of
columns
The columns must also have similar data types
The columns in each SELECT statement must also be in the same order
SELECT company.company_name, company.company_telephone
FROM company
WHERE company.company_id =1
UNION
SELECT contact.contact_fullname, contact.contact_fullname
FROM company
JOIN contact ON company.company_id = contact.works_for_company_id
WHERE company.company_id =1
LIMIT 0 , 30

mysql inner join interrogate 3 tables

I have a table in a MySQL DB, called ‘users’. The fields for users are : id, email, username, first_name, last_name. Another table in the same MySQL DB, called ‘premium_users’ , contains 2 fields : user_id, premium_service_id. A third table called ‘premium_services’ contains 2 fields : premium_service_id , premium_service_name.
I want to create an SQL query , to interrogate my db, so i can have a full list of what premium services has every premium user. How can i interrogate properly with inner join? I’ve try this :
select * from users inner join premium_users on users.id = premium_users.user_id inner join premium_services on premium_users.premium_service_id = premium_services.premium_service_id;
Since you say which service has every user, you'll need to use aggregation to determine this. Here's one way:
select user_id
from premium_users
group by user_id
having count(*) = (select count(*) from premium_services)
SQL Fiddle Demo
Depending on your data, you may need count(distinct premium_service_id) instead, but you should have constraints that don't allow duplicates in those table.
Rereading your question, I might have got this backwards. Looks like you want a list of premium services instead of users. Same concept applies:
select ps.premium_service_id
from premium_services ps
join premium_users pu on ps.premium_service_id = pu.premium_service_id
group by ps.premium_service_id
having count(distinct pu.user_id) = (select count(distinct user_Id) from premium_users)
More Fiddle

"Join" admins of different tables into a string

The real issue
Involved tables and their columns
accounts [id,name]
rooms [id,name,topic,owner]
room_admins [account_id,room_id]
Q: Get all rooms with their admin- and owner ids.
Where "all" of course has a condition to it (above: WHERE name LIKE ...)
Admins and owners should be returned in one column just called "admins". I tried to concatenate them above into one string.
What I tried
I came up with a solution, but it requires the use of an omnious external variable ":room_id" that changes on each outer SELECT and makes therefore no sense at all.
SELECT id,name,topic,
(SELECT GROUP_CONCAT(admins.account_id) AS owner
FROM
(SELECT account_id
FROM `room_admins`
WHERE room_id=:room_id
UNION
SELECT owner FROM `rooms` WHERE id=:room_id) admins) AS owner
FROM `rooms`
WHERE name LIKE "%htm%" OR topic LIKE "%htm%" LIMIT 20
Well, I haven't given this a deep thought... but I've just came up with this (sample data would have been useful to make tests... so this is just a blind answer).
select id, name, topic, group_concat(owner_admin) from (
select id, name, topic, owner owner_admin from rooms
union
select id, name, topic, account_id from rooms
left join room_admins on id = room_id
) s
where name like "%htm%" or topic like "%htm%"
group by id, name, topic
Basically I'm just generating a derived table with owner and admins mixed in one column. Then performing the grouping on that mixed column.
Most of the times, when you want to select and display dependent data, you want to use a JOIN. In this case, you want to join the rooms with their admins, so basically:
SELECT r.id, r.name, r.topic, a.id
FROM rooms r
LEFT JOIN admins a
ON r.id = a.room_id
WHERE :condition
Since you have one additional admin not in the admins table (the room owner), you have to (self) join a second time:
SELECT r.id, r.name, r.topic, a.id
FROM rooms r
LEFT JOIN admins a
ON r.id = a.room_id
LEFT JOIN rooms o
ON r.id = o.id
WHERE :condition
This doesn't give us any new information, but your question states that you want to return the list of admins in a single field. So, finally, putting it all together:
SELECT r.id, r.name, r.topic, GROUP_CONCAT(a.id)
FROM rooms r
LEFT JOIN
(
SELECT id, room_id FROM admins
UNION SELECT room.owner AS id, rooms.id AS room_id FROM rooms
) a
ON r.id = a.room_id
WHERE :condition
GROUP BY r.id
But to avoid this ugly sub-select-union clause, I'd advise you to put the room owner into your admin table too.

M:N relation an query

i've some problems with a specific mysql query an an specific construct.
There are 2 tables:
table users (id, username)
table groups (id, groupname)
these 2 tables are in an m:n relation, but there are 2 tables for that.
First in maps user to groups
table usertogroups (idmaster, idslave)
where idmaster is related to users.id and idslave is related groups.id
Second maps groups to users
table groupstouser (idmaster, idslave)
where idmaster is related to groups.id an idslave is related to users.id
Depend on the application it could not be changed.
Now i want to get all groups with the depending users in one query with the relation of both table, groupstouser and usertogroups.
I've tried al lot of statements, but if I take the second table in it doesn't work.
Any helpfull Ideas?
Use this as an inline view to get the data from both association tables :
((SELECT idmaster AS userid, idslave AS groupid FROM userstogroup)
UNION
(SELECT idslave AS userid, idmaster AS groupid FROM groupstouser)) all_associations
Then you can query like this :
SELECT groups.groupname, users.username
FROM groups
INNER JOIN ((SELECT idmaster AS userid, idslave AS groupid FROM userstogroup)
UNION
(SELECT idslave AS userid, idmaster AS groupid FROM groupstouser)) all_associations
ON groups.id = all_associations.groupid
INNER JOIN users
ON users.id = all_associations.userid
And here's an SQL Fiddle.
I am not sure, it might solve your problem:
(SELECT * FROM usertogroups WHERE idmaster=10)
UNION
(SELECT * FROM groupstouser WHERE idslave=10)
I think your database design is wrong.
When a user is assigned to a group only single table can be used for it. You must be saving duplicate records in both usertogroups and groupstouser.
Try to get your data from only single table.
SELECT * FROM usertogroups order by idslave
If I am wrong that you are not saving duplicate data in both the tables, then specify reason of having two tables

Mysql group concat on double join

I have a user table from which I want all values, so I have this query:
SELECT tbl_user.* FROM tbl_user
Now I want one additional column in this result which shows all roles this user has, (or nothing if there are no roles for the user). The role information comes from two additional tables.
The first table contains these two values: userid, roleid
The second table contains roleid and role_name.
So the group concat needs to get all role names based on the roleid's in table1.
I have tried several different ways to do this, but I don't succeed. Either I get only one result with several times the same rolename, or no result at all.
Thanks for your help
Michael
Update: added LEFT JOIN for users with no role.
SELECT
tbl_user.*,
GROUP_CONCAT(role_name) AS roles
FROM
tbl_user LEFT JOIN tbl_roles ON tbl_user.userid = tbl_roles.userid
JOIN tbl_rolenames ON tbl_roles.roleid = tbl_rolenames.roleid
GROUP BY tbl_user.userid
Note that MySQL will permit a GROUP BY on fewer columns than appear in the SELECT list in total, but in other RDBMS you would need to explicitly list out the columns in tbl_user and include them in the GROUP BY, or do an additional self join against tbl_user to get the remaining columns from that table.
Something like:
SELECT
urole.userid,
uall.username,
uall.name,
uall.othercols,
urole.roles
FROM
tbl_user uall JOIN (
SELECT
tbl_user.userid,
GROUP_CONCAT(role_name) AS roles
FROM
tbl_user LEFT JOIN tbl_roles ON tbl_user.userid = tbl_roles.roleid
JOIN tbl_rolenames ON tbl_roles.roleid = tbl_rolenames.roleid
GROUP BY tbl_user.userid
) urole ON uall.userid = urole.userid