how to join 2 mysql tables - mysql

I want to join two tables to get data from both tables, for example, consider two following tables:
Table users:
ID user_name email ... ....
Table messages:
ID user_name message ... ...
The user_name is common column in both tables. How can I join both tables so that I can get the data from both tables. For example, I want to select the "message" from Table messages and "email" from table "users" where user_name is abc.

Use:
SELECT u.*, m.*
FROM USERS u
JOIN MESSAGES m ON m.user_name = u.user_name
WHERE u.user_name = 'abc'
...to see all the users who have messages in the tables. That means that users without messages will not appear in the output - so you might want to use the following instead:
SELECT u.*, m.*
FROM USERS u
LEFT JOIN MESSAGES m ON m.user_name = u.user_name
WHERE u.user_name = 'abc'
I recommend:
reading the Visual Explanation of JOINs.
not using a user_name as the criteria to link data between tables, because usernames can change which would require updating all the supporting tables in this example.
not using ANSI-89 join syntax, because it doesn't support OUTER joins and should be considered deprecated for that fact. My example is ANSI-92 syntax, and widely supported.

If you take a look at the MySQL website, there are a lot of examples on there. For the most part, people would be happier to answer if you had show some queries you'd tried and not got the results you wanted.
select users.user_name, users.email, messages.message from users,messages where users.user_name=messages.user_name where users.user_name='abc'
This is a fairly elementary SQL statement. There's a lot of clever stuff you can do. You would be wise to go see what else you can do, as rather than embed the 'abc' part you can use parameters etc.

SELECT message, email
FROM users U, messages M
WHERE U.user_name = 'abc' AND U.user_name = M.user_name;

select m.message, u.email
from
messages m join users u on
m.user_name = u.user_name
where
u.user_name = 'abc'

If you want the data that matches in both tables (so not a user without a message):
SELECT * FROM users u, messages m WHERE u.user_name = m.user_name;
If you want all users regardless of messages and messages for those users who have them:
SELECT * FROM users u LEFT JOIN (messages m) ON (u.user_name = m.user_name);
EDIT: Sorry, I misread.
SELECT * FROM users u, messages m WHERE u.user_name = m.user_name AND u.user_name = "abc";

Related

Join results from two tables when data can appear in multiple columns in one table

I have one table containing a list of users, all I need from this are users.id and users.username
I have a second table that links the users as "friends", all I need from this is friends.one and friends.two
I want to output a result that shows all friends of a user with a certain user id (this will be a variable, but for the sake of the example we'll use user id '1'). User id '1' can appear in either friends.one or friends.two.
I've tried a few different ideas, but I'm not sure I'm any closer. The code below is obviously awful but I think it describes the idea well(ish). Though I'm probably overly complicating something which there is an easier method for,
SELECT users.username, users.id
FROM users
INNER JOIN friends
ON users.id = friends.friendone
WHERE friends.friendtwo='1'
UNION
SELECT users.username, users.id
FROM users
INNER JOIN friends
ON users.id = friends.friendtwo
WHERE friends.friendone='1'
ORDER BY users.username ASC;
With conditional join:
SELECT u.username, u.id
FROM friends f INNER JOIN users u
ON u.id = CASE '1'
WHEN f.friendone THEN f.friendtwo
WHEN f.friendtwo THEN f.friendone
END

mySQL SELECT help. IF or EXISTS?

I have this DB structure
* user
user_id
name
* client
client_id
name
* user_client
user_client_id
user_id
client_id
* message
message_id
client_id
description
If there are entries on user_client then the user has permissions restricted to the specific clients listed for his id on the table. If there are no entries, then the user has access to any client.
How can I select only messages that the user can read?
I'm trying to do an IF on the WHERE clause to check if any entries on the user_client table but I don't know where to go from there. It needs to select all messages from any client if no entries on user_client or only messages for client_id specified on user_client table
Thanks for the help!
I would suggest doing two different queries: one for the superusers and the other for the restricted users. Then you can join the two results with a UNION.
SELECT M.message_id,
M.client_id,
M.description
FROM message M
INNER JOIN user_client UC ON (UC.client_id = M.client_id)
INNER JOIN user U ON (UC.user_id = U.id)
WHERE U.id = :user_id
UNION
SELECT M.message_id,
M.client_id,
M.description
FROM message M
WHERE NOT EXISTS (
SELECT *
FROM user_client
WHERE user_id = :user_id
)
You can obtain the same result with other queries but IMHO this one is clearer and more maintainable.
Edit: If you want to ensure that the user exists you should join the second query with the user table.
SELECT M.message_id,
M.client_id,
M.description
FROM message M
JOIN user U
WHERE U.id = :user_id
AND NOT EXISTS (
SELECT *
FROM user_client
WHERE user_id = :user_id
)
One way the do this could be to use two different queries to create a set of the messages users can see and filter according to your needs; something like this should work:
select * from (
select u.user_id, u.name, c.name client, m.message_id, m.description
from user u
join user_client uc on u.user_id = uc.user_id
join client c on uc.client_id = c.client_id
join message m on c.client_id = m.client_id
union all
select u.user_id, u.name, c.name client, m.message_id, m.description
from user u
cross join client c
join message m on c.client_id = m.client_id
where user_id not in (select user_id from user_client)
) x
where x.user_id = 1;
Here users present in the user_client table are restricted to the set of messages that they have access to (the first set in the union), while users not present in the user_client table can see all messages (the second set in the union).
Sample SQL Fiddle
If I am understanding your question correctly, such as
1) Administrative user... They can look at EVERYTHING since they would have no records in the user_client table.
2) Client Supervisor... Such a person who's primary responsibility is to a specific client (or multiple clients). Therefore, the user DOES have a record in the user_client table. If so, then only allow the user to see records for those clients they DO have associations with.
select
m.message_id,
m.client_id,
m.description,
c.name as clientName
from
( select count(*) as HasClients
from user_client
where user_id = TheUserYouWant ) ClientCheck,
message m
left join user_client uc
on m.client_id = uc.client_id
AND uc.user_id = TheUserYouWant
join client c
on m.client_id = c.client_id
where
ClientCheck.HasClients = 0
OR NOT uc.user_id IS NULL
The query looks at the user_client table TWICE. The first time is to just get a count of those records that DO exist for the given user, regardless of which client associated with. The query will always come back with 1 row and it will either be 0 (no such records), or greater than 1 (however many they are associated with).
The second instance is a LEFT-JOIN to the user_client table, JUST IN CASE the person IS restricted to only looking at their own client messages.
The WHERE clause now comes in and says... if the underlying count of clients was zero, then ok to give me all messages. If any other value, then the user ID in the user_client table (as left-joined to the messages on both the CLIENT AND THE USER you want) MUST EXIST (via NOT a NULL value for the user_id column).
Now, you probably don't want to query EVERY message as it could get quite large as your database grows, but you could put whatever other criteria in the WHERE clause, such as date restrictions and/or client(s) you are interested in.

SQL Query shows no result with left join

I have the following query:
SELECT u.user_id, u.username, u.email
hp.homepage_id
FROM table_u u
LEFT JOIN table_hp hp
ON (u.user_id = hp.user_id)
WHERE u.blocked = 'N'
AND u.email LIKE 'someemailaddress'
I am joining on the user_id column, for the given emailadress I know both properties are the same so I should get a result but still I don't get any result... so what is wrong with this query?
Put the '%' before and after in the LIKE clause - see below
SELECT u.user_id, u.username, u.email
hp.homepage_id
FROM table_u u
LEFT JOIN table_hp hp
ON (u.user_id = hp.user_id)
WHERE u.blocked = 'N'
AND u.email LIKE '%someemailaddress%'
Did you try the query without LEFT JOIN ??
SELECT u.user_id, u.username, u.email
FROM table_u u
WHERE u.blocked ='N'
AND u.email LIKE 'someemailaddress'
Does it return any result? Cause LEFT JOIN just append data for the existing data from your "base table" .. so if the LEFT JOIN didn't find any user_id in table_hp there should be some data returned, if there are some from the query above
The point was how some data was stored in the database... Seems that in an old (buggy) version of the application data was stored without decent trimming etc. The issue was the field was stored in with a whitespace...
Stupid... should/must had checked the actual data that was stored...

SQL query to exclude one to many that have a specific value?

Using MySQL, I'd like to list all users that don't have the document "liaison". It could means Users that does not have any document at all, or users that have documents, but not "liaison" in these ones.
How can I do using MySQL Query ? I can't make it work!
Here's the (simple) model
Users (id, name)
Documents (id, user_id, name, path)
The NOT EXISTS is a workable solution. As an alternative, sometimes, with large sets, an "anti JOIN" operation can give better performance:
SELECT u.*
FROM Users u
LEFT
JOIN (SELECT d.user_id
FROM Documents d
WHERE d.name = 'liaison'
) l
ON l.user_id = u.id
WHERE l.user_id IS NULL
The inline view aliased as l returns us a list of user_id that have document named 'liaison'; that result set gets outer joined to the Users table, and then we exclude any rows where we found a match (the test of l.user_id IS NULL).
This returns a resultset equivalent to your query with the NOT EXISTS predicate.
Another alternative is to use a query with a NOT IN predicate. Note that we need to guarantee that the subquery does not return a NULL, so the general approach is to include an IS NOT NULL predicate on the column being returned by the subquery.
SELECT u.*
FROM Users u
WHERE u.id NOT IN
( SELECT d.user_id
FROM Documents d
WHERE d.user_id IS NOT NULL
AND d.name = 'liaison'
)
I'd write the NOT EXISTS query like this:
SELECT u.*
FROM Users u
WHERE NOT EXISTS
( SELECT 1
FROM Documents d
WHERE d.name = 'liaison'
AND d.user_id = u.id
)
My personal preference is to use a literal 1 in the SELECT list of that correlated subquery; it reminds me that the query is just looking for the existence of 1 row.)
Again, I usually find that the "anti-join" pattern gives the best performance with large sets. (You'd need to look at the EXPLAIN output for each statement, and measure the performance of each to determine which will work best in your situation.)
The correct query you are looking for is:
SELECT
*
FROM
Users
WHERE
id NOT IN (
SELECT
user_id
FROM
Documents
WHERE
name = "liaison"
)
This will achieve the exact result you are looking for. If a specific user has no documents, it will be listed. If it has many documents, and one of those is 'liaison', it won't be listed.
If you want to search for 'liaison' in your document's name, replace name = "liaison" for name LIKE "%liaison%".
It basically says: Select all users such as there are no documents with name "liaison" pointing to it.
So, I finally came up with this solution that seems to work good :
SELECT * FROM users u WHERE id NOT IN (SELECT DISTINCT user_id FROM user_documents WHERE name = 'LIAISON') ORDER BY c.lastname, c.firstname
SELECT users.*
FROM users left join Documents
on users.id = Documents.user_id
and documents.name='LIAISON'
WHERE documents.user_id is null
select * from Users where not exists (select id from Documents where Users.id = Documents.id and Documents.name = 'liaison')
Try :
SELECT DISTINCT u.*
FROM users u LEFT JOIN documents d ON d.user_id = u.id
WHERE d.id IS NULL OR d.name NOT LIKE '%liaison%'
Remove percent signs if "liaison" is the exact name of the document.

Complex? MySQL Join SELECT query

I'm trying to get a list of 'contacts' for a specified user id.
Let says my user id is 1, i need to get the list of ids of my my contacts from chat-contactlist then get all the infos for each id.
All users' id, name and contact information
Table usr: uid, rname, phonenumber
Online status and other stuff
Table chat-usr: uid, nickname, online_status
Containing user id and the user id of each contact this user have :
Table chat-contactlist: uid, cid (cid = The id of the person who's int he "uid" user list
So I need the name, the nickname, the online_status for all the 'cid' for a specified 'uid'... Dont know i read a tutorial about left join but it seams complex to merge multiple tables, anyone wanna try? Any recommendation?
Thank you
EDIT
Changing name by rname because name is a reserved word for SQL.
This is a 3-table join where you have a many-to-many relationship defined by the linker table chat-contactlist:
SELECT u.name username, c.nickname chat_username, c.online_status
FROM chat-contactlist cc
JOIN usr u ON (u.uid = cc.uid)
JOIN chat-usr c ON (c.uid = cc.cid);
This is an explicit join. If you are looking to select a specific user, you would add that in WHERE clauses afterward.
SELECT u.name username, c.nickname chat_username, c.online_status
FROM usr u, chat-usr c, chat-contactlist cc
WHERE cc.uid = u.uid
AND cc.cid = c.uid;
This is an implicit join, where the tables are related by equality in WHERE statements. It isn't recommended to use but I find them sometimes easier to read.
More info:
Basic many-to-many left join query
Explicit vs Implicit Joins
SELECT ccl.uid,
Name = u.Name,
Nickname = cu.nickname,
OnlineStatus = cu.onlinestatus
FROM chat-contactlist ccl
JOIN chat-usr cu ON ccl.cid = cu.uid
JOIN usr u ON u.uid = cu.uid
Where ccl.uid = #uid /* your filter here */