Complex? MySQL Join SELECT query - mysql

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 */

Related

SQL matching IDs from different columns with their respective username

I have a table containing the columns user_id and lastreply_by_user_id and I'm looking for a way to match their columns with their username from the user table with id.
SELECT
table_threads.*,
table_users.username
FROM
threads AS table_threads
INNER JOIN users as table_users ON table_threads.user_id = table_users.id
OR table_threads.lastreply_by_user_id = table_users.id
WHERE
table_threads.category_id = :category_id
This is the code I have right now but this at the moment creates duplicate entries instead of one merged.
Just started with SQL recently and found the JOIN commands maybe it isn't the right one just point me in the right direction and I'll be thankful.
You need two joins to the same user table for that: one to connect by user_id, and one more to connect by lastreply_by_user_id. Use table aliases for disambiguation:
SELECT
t.*,
u.username as user_name,
r.username as last_reply_name
FROM
threads AS t
INNER JOIN users as u ON t.user_id = u.id -- actual user
INNER JOIN users as r ON t.lastreply_by_user_id = r.id -- reply user
WHERE
table_threads.category_id = :category_id

Better MySQL query?

Here's one example, I have a Car, User, Member, and Dealer tables. At the moment I'm trying to get the name of a dealer who owns a car by matching their userids up
Select userid, name FROM `User` WHERE userid IN
(SELECT userid FROM 'Car' WHERE userid in
(SELECT userid FROM `Member` WHERE userid IN
(SELECT userid FROM `Dealer`)))
This does what I want but I can't help feel there's a better way of doing it? Currently the userid in Car is a FK of the userid in Dealer which is a FK of the userid in Member which is a FK of the userid in User which stores the name.
Can I go straight to getting all the userid's and names of dealers who's id is in the Car table, whilst making sure they're actually a Dealer?
Basically your schema is a downstream schema
Users -> Members -> Dealer -> Car
Good thing is you made all the possible keys that you need here.
So to selct anything in any table just go down stream from Users for example for the data you want
Select * from `USER` u
where
dealer.user_id = car.user_id and
member.user_id = dealer.user_id and
u.user_id = member.user_id
The reason i went upstream in matching records is because we want to make as few matching operations as possible. As you can see user table is supposed to contain the maximum records. So i match with car table and get all the user_id where there is a match in dealer. similarly i go from dealer to member and then to user. this means all the records of users will be matched with a lot fewer records that they would have been if i went from users to members to dealer to car.
But this is not fool proof solution. it will depend on your data. because it may be a case where one user may have multiple cars, then it would be better to go downstream.
Use JOIN instead of subqueries to fetch the data.
Try this:
SELECT U.userid, U.NAME
FROM `User` U
INNER JOIN Car C ON U.userid = C.userid
INNER JOIN Member M ON C.userid = M.userid
INNER JOIN Dealer D ON M.userid = D.userid;

Select different values from one table based on another table

So, the two tables in question:
userinfo: id(PK), users_id(FK to users table), name, surname
doctorpatient: id(PK), doctor_id(FK to users table), patient_id(FK to users table)
The idea is each doctor is assigned a few patients via the doctorpatient table. What I want to do is return an array of arrays, where each of the inner arrays contains this:
users_id(doctor), name(doctor), surname(doctor), users_id(patient), name(patient), surname(patient)
Can this even be done using purely SQL? I tried this:
SELECT userinfo.users_id,
userinfo.name,
userinfo.surname,
u2.users_id,
u2.name,
u2.surname
FROM doctorpatient
RIGHT OUTER JOIN userinfo
ON doctorpatient.doctor_id = userinfo.users_id
LEFT OUTER JOIN userinfo AS u2
ON doctorpatient.patient_id = u2.users_id
but no matter what combination of joins I try, it never comes out right. I tried getting the data in three separate queries and then somehow get the result I need using PHP, but I got nowhere with that.
Edit: What I want is this:
array(
subarray1(patient_id1,
patient_name1,
patient_surname1,
doctor_id1,
doctor_name1,
doctor_surname1)
subarray2(patient_id2,
patient_name2,
patient_surname2,
doctor_id1,
doctor_name1,
doctor_surname1)
etc...
where one doctor can have multiple patients. What my query gets me looks something like this:
array(
subarray1(patient_id1,
patient_name1,
patient_surname1,
)
subarray2(patient_id2,
patient_name2,
patient_surname2,
)
etc...
But most of the data is null.
I think a simple JOIN may be sufficient. The OUTER JOINs appear to be causing the null values because it tries to treat the doctors as patients.
SELECT u1.users_id AS doctor_id,
u1.name AS doctor_name,
u1.surname AS doctor_surname,
u2.users_id AS patient_id,
u2.name AS patient_name,
u2.surname AS patient_surname
FROM doctorpatient AS d JOIN userinfo AS u1 ON d.doctor_id = u1.users_id
JOIN userinfo AS u2 ON d.patient_id = u2.users_id
Try this:
SELECT
u.id as user_id,
u.name as user_name
u.surname as user_usrname
d.id as doc_id,
d.name as doc_name,
d.surname as doc_surname
FROM doctorpatient as dp
LEFT JOIN userinfo as u ON (dp.pacient_id = u.id)
LEFT JOIN userinfo as d ON (dp.doctor_id = d.id)

table with multiple foreign keys joining 1 foriegn key in mysql

Hi I have a database table with the following information :
owner.primaryitowner, (bobsmith#mail.com)
owner.secondaryitowner,
owner.primarybusinessowner,
owner.secondarybusinessowner
users.username (email bobsmith#mail.com)
users.displayname (e.g. Bob Smith)
The issue, is the owners are only stored as emails. There is another table I normally
inner join users on users.username = owner.primaryitowner to get users.displayname
so the data reads correctly.`
I am able to do this
select u.displayname
from users u
inner join owners o on
o.primaryitowner = u.username
or o.secondaryitowner = u.username
or o.primarybusinessowner = u.username
or o.secondarybusinessowner = u.username
The issue is I need to have unique columns not all into one column.
PS I cannot change the database I am only a report writer.
Thanks so much in advance
You will want to join each column of email from users into owners
SELECT u.displayname AS userName
, po.displayName AS PrimaryItOwnerUsernName
, so.displayName AS SecondaryIdOwnerUserName
FROM users AS u
INNER JOIN owners AS po on u.primaryitowner = po.username
INNER JOIN owners AS so ON u.secondaryitowner = so.username
...
WHERE u.UserName = 'Ryan J Morse'
When you join into the owners table (aliased) multiple times, this allows you to change the emails stored in users into the display names you will need for your report.
Does this work for your needs? When you come at it from the point of view of the owner table, it's easier to grab all of the displayname's as separate columns for a single owner record. Going the other way will pull information from muliple owner records for the same user. If that's what you want, then this won't work.
select prim_o.displayname as "Primary IT Owner",
sec_o.displayname as "Secondary IT Owner",
prim_bo.displayname as "Primary Business Owner",
sec_bo.displayname as "Secondary Business Owner"
from owner o
inner join users prim_o (o.primaryitowner = prim_o.username)
inner join users sec_o (o.secondaryitowner = sec_o.username)
inner join users prim_bo (o.primarybusinessowner = prim_bo.username)
inner join users sec_bo (o.secondarybusinessowner = sec_bo.username)

Join mysql tables twice on 2 columns = 1 column

I have a database that contains messages. The messages are stored in one table, the user information is stored in another. In the message table, there is an author_id column which represents the user_id of the author from the user table, there are all the message columns, and there is a to_address which represents a concatenation of "u_" + user_id from the user table. Is there any that I can join these two tables, so that it display the username instead of ID in BOTH the author_id AND to_address.
I've tried
SELECT username, ..., username
FROM msgs
INNER JOIN users
ON user_id=author_id AND concat("u_",user_id)=to_address;
with obvious error
I've tried using subqueries such as
SELECT
( SELECT username
FROM users
INNER JOIN msgs
ON user_id=author_id
) AS "From",
( SELECT username
FROM users
INNER JOIN msgs
ON CONCAT("u_",user_id)=to_address
) AS "To",
( SELECT timestamp(message_time) FROM msgs
) AS "Sent",
( SELECT message_subject FROM msgs
) AS "Subject",
( SELECT message_text AS "Message" FROM msgs
) AS "Message"
and got "Subquery returns more than 1 row". Is there any way that I can do this successfully?
It sounds like you want something like this:
SELECT
from_user.username AS "From",
to_user.username AS "To",
timestamp(msgs.message_time) AS "Sent",
msgs.message_subject AS "Subject",
msgs.message_text AS "Message"
FROM msgs
INNER JOIN users AS from_user
ON msgs.author_id = from_user.user_id
INNER JOIN users AS to_user
ON msgs.to_address = CONCAT("u_", to_user.user_id);
Basically, you join the users table to the msgs table twice, giving each instance of the table a different name and a different join condition. Then you can pick a specific column out of a specific instance of the users table.
I think you want to do something like
SELECT msgs.*,
authors.whatever,
addresses.to_address
FROM msgs
JOIN users AS authors ON msgs.author_id = authors.id
JOIN users AS addresses ON msgs.address_id = addresses.id
My query is perhaps imprecise but you can probably see what I'm doing here.
As an aside, I would recommend not abbreviating msgs and using singular table names.
You need two joins as you want to get two separate users:
select f.username, t.username
from msgs m
inner join users f on f.user_id = m.author_id
inner join users t on concat("u_", t.user_id) = m.to_address
This will return the username associated with both the "author_id" and the "to_address", using correlated subqueries, instead of using JOIN. (Using a JOIN is the usual approach, but an approach using a correlated subquery gives you some additional flexibility.
SELECT (SELECT u.username
FROM users u
ON u.user_id = CONCAT("u_",u.user_id) = m.to_address
ORDER BY u.username LIMIT 1
) AS to_username
, (SELECT a.username
FROM users a
ON a.user_id = m.author_id
ORDER BY a.username LIMIT 1
) AS author_username
, m.*
FROM msgs m
NOTE: this differs a bit from an INNER JOIN in that this will return a row from msg when a matching username is not found for the to_address or the author_id.)
NOTE: this assumes that user_id is unique in the users table.
NOTE: if the username column is NOT NULL in the users table, then you can emulate the INNER JOIN, and NOT return a row if a matching username is not found for the author_id or to_address by adding
HAVING to_username IS NOT NULL
AND author_username IS NOT NULL