Query two tables with result opposite of join like statement - mysql

Here is the simple question to gain some medals :) :
I have three tables:
"contacts" that holds the contacts information where each entry has a unique id.
The second table "groups" where is stores the name for each group and the group id.
The last "contacts_groups" binds each contact to a group, it has just two columns, contact_id and group_id.
The question is how do write in a single statement a MySQL query that will select all contacts that are not assigned to a group. In other words contacts which id is not listed in "contacts_groups" table?

select * from contacts c
left outer join contacts_groups cg on c.id = cg.contact_id
where cg.contact_id is null

SELECT * FROM contacts c
WHERE NOT EXISTS (SELECT * FROM contacts_groups cg
WHERE cg.contact_id = c.contact_id)

Just to be complete, here's another solution:
SELECT * FROM contacts
WHERE contact_id NOT IN (SELECT contact_id FROM contacts_groups)
However, I think MySQL tends to execute the left join or correlated subquery more efficiently.

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

Select rows that are referenced in another table

I have two tables and they are as follows:
USERS
ORDERS
I want select all users who have at least 1 order or more in the ORDERS table. I know there is an inline query for this in MySQL, but right now I have to select all users and then make another query seeing if each user has an order - all this using a PHP loop.
What I am doing now is not ethically correct, so I basically just want to select all users who have been referenced in the ORDERS table in ONE MySQL query.
This is a query you should be using
select distinct u.* from users u
inner join orders o on o.user_id = u.id;
Note the distinct and u.*. This query will not select fields from orders and it will not select the same user twice (if one has more than one order).
Demo: http://sqlfiddle.com/#!2/6ebcc/3
You can use mysql join syntax. Assuming both of your tables has userid column, this is the example :
SELECT * FROM USERS a JOIN ORDERS b ON
a.UserId = b.UserId
This is a simple database operation, see here for the explanation join

MySQL Left Join Multiple Rows

I have an interesting challenge... I have two tables, products and users.
products contains 2 columns, user_id and current_bidder, which hold two different IDs from the users table.
I would like to select all columns from products, and the name and rating from the users table for each user_id and current_bidder.
Essentially, I'm trying select columns from two different rows on a joined table, while disambiguating their names.
Any help would be greatly appreciated.
Join to the user table twice, and give each copy a different alias. Something like this:
select p.name, p.weight, owner.name, bidder.name
from product p
join user owner
on ...
join user bidder
on ...
The nice way to avoid ambiguity between columns is to add an ALIAS on it.
SELECT a.*, -- selects all records from products
b.name AS user_name, -- user_name is an alias of users.name (user_id)
c.name AS bidder_name -- user_name is an alias of users.name (current_bidder)
FROM products a
LEFT JOIN users b
ON a.user_id = b.id
LEFT JOIN users c
ON a.current_bidder = c.id
The reason why I used LEFT JOIN is because I assumed that some products has no bidder yet. If INNER JOIN was used, product will never be shown on the result until there's a bidder on it.

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

MySQL returning results from one table based on data in another table

Before delving into the issue, first I will explain the situation. I have two tables such as the following:
USERS TABLE
user_id
username
firstName
lastName
GROUPS TABLE
user_id
group_id
I want to retrieve all users who's first name is LIKE '%foo%' and who is a part of a group with group_id = 'givengid'
So, the query would like something like this:
SELECT user_id FROM users WHERE firstName LIKE '%foo'"
I can make a user defined sql function such as ismember(user_id, group_id) that will return 1 if the user is a part of the group and 0 if they are not and this to the WHERE clause in the aforementioned select statement. However, this means that for every user who's first name matches the criteria, another query has to be run through thousands of other records to find a potential match for a group entry.
The users and groups table will each have several hundred thousand records. Is it more conventional to use the user defined function approach or run a query using the UNION statement? If the UNION approach is best, what would the query with the union statement look like?
Of course, I will run benchmarks but I just want to get some perspective on the possible range of solutions for this situation and what is generally most effective/efficient.
You should use a JOIN to get users matching your two criteria.
SELECT
user_id
FROM
users
INNER JOIN
groups
ON groups.user_id = users.users_id
AND groups.group_id = given_id
WHERE
firstName LIKE '%foo'
You don't need to use either a UNION or a user-defined function here; instead, you can use a JOIN (which lets you join one table to another one based on a set of equivalent columns):
SELECT u.user_id
FROM users AS u
JOIN groups AS g
ON g.user_id = u.user_id
WHERE g.group_id = 'givengid'
AND u.firstName LIKE '%foo'
What this query does is join rows in the groups table to rows in the users table when the user_id is the same (so if you were to use SELECT *, you would end up with a long row containing the user data and the group data for that user). If multiple groups rows exist for the user, multiple rows will be retrieved before being filtered by the WHERE clause.
Use a join:
SELECT DISTINCT user_id
FROM users
INNER JOIN groups ON groups.user_id = users.user_id
WHERE users.firstName LIKE '%foo'
AND groups.group_id = '23'
The DISTINCT makes sure you don't have duplicate user IDs in the result.