MySQL query for add join after check column - mysql

I have created database with following tables.
booking (id, user_id, user_table, date);
user (id, fname, lname);
tmp_user (id, fname, lname);
The user_id of booking table refer both user table id and tmp_user table id. I use user_table column for keep user table type.
I want to write a query to get booking details with user details. So i should check user_table column value before join user table.
Is it possible? How can i do that?

You can do a query of this type by joining both in and then using precedence:
select b.*,
(case when u.id is not null then u.fname else tu.fname end) as fname,
(case when u.id is not null then u.lname else tu.lname end) as lname
from booking b left outer join
user u
on b.user_id = u.id left outer join
tmp_user tu
on b.user_id = tu.id
You can also add in the condition and u.uid is null to the second join. I don't know if that would help or hinder performance.
Oh, if you want the user table value, then that is just a small modification to the logic:
select b.*,
(case when b.user_table = 'user' then u.fname else tu.fname end) as fname,
(case when b.user_table = 'tmp_user' then u.lname else tu.lname end) as lname
from booking b left outer join
user u
on b.user_id = u.id left outer join
tmp_user tu
on b.user_id = tu.id;

Related

MySQL: joining three tables and returning all rows

I have these three tables:
user (id, name)
activity (id, name)
enrolment (id, user_id, activity_id)
I need to return a list of all users, and for each of them return all the activities as well as whether or not there is an enrolment record for that user and that activity.
So, if I have 3 activities, it would return something like this:
user1 activity1 "not enrolled"
user1 activity2 "enrolled"
user1 activity3 "not enrolled"
user2 activity1 "enrolled"
user2 activity2 "enrolled"
user2 activity3 "not enrolled"
etc...
I've tried a few join combinations but with no luck so far... Any tip would be greatly appreciated.
EDIT:
The solutions for this case, provided by Barmar below, is:
SELECT u.name AS user, a.name AS activity, IF(e.id IS NULL, 'not enrolled', 'enrolled') AS enrolled
FROM user AS u
CROSS JOIN activity AS a
LEFT JOIN enrolment AS e ON u.id = e.user_id AND a.id = e.activity_id
ORDER BY u.name, a.name
However there is an added complication. I tried to simplify the matter by putting an activity_id field in the enrolment record, but actually the link between enrolment and activity is in a separate table:
user (id, name)
activity (id, name)
enrolment (id, user_id)
enrolment_activity (id, activity_id, enrolment_id)
So I've tried the following:
SELECT u.name AS user, a.name AS activity, IF(e.id IS NULL, 'not enrolled', 'enrolled') AS enrolled
FROM user AS u
CROSS JOIN activity AS a
LEFT JOIN enrolment AS e ON u.id = e.user_id
LEFT JOIN enrolment_activity AS ea ON (ea.activity_id = a.id AND ea.enrolment_id = e.id)
ORDER BY u.name, a.name
But it doesn't seem to return the correct result (lots of duplicates and the enrolment column is not correct anymore)
EDIT 2:
Figured it out by using a subquery. Not sure if that's the most efficient way, but it worked:
SELECT u.name AS user, a.name AS activity, IF(e.id IS NULL, 'not enrolled', 'enrolled') AS enrolled
FROM user AS u
CROSS JOIN activity AS a
LEFT JOIN enrolment AS e ON u.id = e.user_id AND a.id = (SELECT activity_id FROM enrolment_activity WHERE enrolment_id = e.id)
ORDER BY u.name, a.name
Cross JOIN between user and activity to get all possible combinations. Then use LEFT JOIN to determine if the user is enrolled in that activity.
SELECT u.name AS user, a.name AS activity, IF(e.id IS NULL, 'not enrolled', 'enrolled') AS enrolled
FROM user AS u
CROSS JOIN activity AS a
LEFT JOIN enrolment AS e ON u.id = e.user_id AND a.id = e.activity_id
ORDER BY u.name, a.name

Creating a new column in an SQL query

I have one table to store users and one table to store member fee payments:
Users
Id (int)
Name (string)
MemberFeePayments
Id (int)
User (int)
Year (int)
The "User" column in MemberFeePayment is a reference (foreign key) to the user that have payed the fee. The "Year" column tells which year the user have payed the fee for. If a user has been a member for several years, there will be multiple rows for the user in the MemberFeePayments table.
Now I would like to write an sql query that fetches ALL users. The resulting table should have a column that tells if the users are members in a specific year (which will be provided to the query):
Result
Id (int)
Name (string)
IsMember (bool)
What is a good way to accomplish this?
I'm using MySql (5.6).
This should work if there is only one Fee Payment record per year:
SELECT
U.Id, U.Name,
CASE WHEN M.ID IS NULL THEN 0 ELSE 1 END AS `IsMember`
FROM Users U
LEFT JOIN MemberFeePayments M ON (U.Id = M.User AND M.Year = 2013)
This will work if you have multiple payments in year:
SELECT
U.Id, U.Name,
CASE WHEN COUNT(M.ID) > 0 THEN 1 ELSE 0 END AS `IsMember`
FROM Users U
LEFT JOIN MemberFeePayments M ON (U.Id = M.User AND M.Year = 2013)
GROUP BY U.Id, U.Name;
Here's a link to a demo
Try this:
SELECT a.Id,a.Name,if(b.id>0,TRUE,FALSE) as ismember FROM USERS a LEFT JOIN MemberFeepayments b ON a.id=b.id
check column fields and table name
Here is a way you can do it. So it will lit all the users no matter they are in the MemberFeePayments table or not and will show Yes if they are member for a particular year else No.
select
x.Id,
x.Name,
case when x.member is not null then 'Yes' else 'No' end as IsMember
from
(
select
u.Id,
u.Name,
m.User as member
from Users u
left join MemberFeePayments m on m.User = u.Id AND m.year = 2014
)x
OR simply as below without doing the outer select from derived table.
select
u.Id,
u.Name,
case when m.User IS NOT NULL THEN 'Yes' else 'No' end as IsMember
from Users u
left join MemberFeePayments m on m.User = u.Id AND m.year = 2014
DEMO
Use left join
SELECT t1.id,t1.Name,t2.id
FROM Users t1
LEFT JOIN MemberFeePayments t2 ON t1.id = t2.user and t2.year = 2014
t2.id will be null if there are no data in MemberFeePayments for that user and year

SQL Query Help 1 to N

I have a MySQL database with a 1 to N relation in there.
Sample Data:
Table User:
ID,Name
Table Entry:
ID,Name
Table User_Entry:
UserID,EntryID
I would like to get all Entries (their ID and NAME) and a flag, that states, if a User with ID x has this Entry (via Table USER_ENTRY)
#GarethD answer is fine but I would go one step further to verify that actual UserID in User_Entry is actual valid user in User table. If you do not have foreign keys on the table it is possible that you have UserID that does not exists in User table. To enforce that check you can join both tables and verify Id from User table in the following manner.
SELECT e.EntryID
,e.NAME
,CASE WHEN u.ID IS NULL THEN 0 ELSE 1 AS UserFlag
FROM Entry AS e
LEFT OUTER JOIN User_Entry AS ue
ON e.id = ue.EntryID
LEFT OUTER JOIN User AS u
ON ue.UserID = u.ID
To go even further you can write case statement to can find bad records by checking both UserID in User_Entry table and checking ID in User table.
SELECT e.EntryID
,e.NAME
,CASE WHEN u.ID IS NULL THEN 0 ELSE 1 AS UserFlag
,CASE WHEN ue.UserId IS NOT NULL AND u.ID IS NULL THEN 1 ELSE 0 END AS InvalidUserID
FROM Entry AS e
LEFT OUTER JOIN User_Entry AS ue
ON e.id = ue.EntryID
LEFT OUTER JOIN User AS u
ON ue.UserID = u.ID
You would need to select from your entry table to get all your entries, and then left join to your user_entry table to find out if a particular user has that entry:
SELECT e.ID,
e.Name,
CASE WHEN ue.EntryID IS NULL THEN 0 ELSE 1 END AS UserFlag
FROM Entry AS e
LEFT JOIN user_Entry AS ue
ON ue.EntryID = e.ID
AND ue.UserID = x
You actually don't need Table C to link the ID's together. This is exactly what a SQL JOIN is for! Try:
SELECT * FROM table_a JOIN table_b WHERE table_a.id = table_b.id

chat application friend list

I have 3 MySQL tables namely chat_comments, chat_friends and user_details and I want to display a friend list.
My tables:
chat_comments(comment_id,comment,user_id,user_id2,date_added)
chat_friends(user_id,user_id2,approved)
user_details(user_id, mainimage_id, fullname)
To do this, I need a query that will return the needed fields (u.mainimage_id, u.fullname, b.comment, b.user_id) so I can loop through the list to display a table.
SQL so far (help from #Andriy M):
SELECT
cc.comment,
cc.date_added,
u.fullname,
u.mainimage_id
FROM
user_details u
LEFT JOIN
chat_comments cc
INNER JOIN (
SELECT
user_id,
MAX(comment_id) AS maxcomment
FROM chat_comments WHERE user_id=2020 OR user_id2=2020
GROUP BY user_id
) a ON a.user_id = cc.user_id
AND a.maxcomment = cc.comment_id
ON a.user_id = u.user_id
WHERE u.user_id IN (
SELECT user_id2
FROM chat_friends
WHERE user_id = 2020
AND approved = 1
)
The above query returns the last comment made by the logged-in user's friends in conversation not the last comment between the logged-in user and his/her friend regardless of who made it.
I would like it to return the last comment between the logged-in user and their friend individually regardless of who made it. In the chat_messages table, user_id is the sender and user_id2 is the receiver. Hope it makes sense?
Like #imm said in a comment, you need to use an outer join. In case of a left join, the user_details table should become the left side of the join, the right side being the result of your inner join of chat_comments with your a derived table. You'll also need to remove the user_id IN (…) condition from inside the a subselect and re-apply it to the user_details table. Here:
SELECT
cc.comment,
cc.date_added,
u.fullname,
u.mainimage_id
FROM
user_details u
LEFT JOIN
chat_comments cc
INNER JOIN (
SELECT
user_id,
MAX(comment_id) AS maxcomment
FROM chat_comments
GROUP BY user_id
) a ON a.user_id = cc.user_id
AND a.maxcomment = cc.comment_id
ON a.user_id = u.user_id
WHERE u.user_id IN (
SELECT user_id2
FROM chat_friends
WHERE user_id = 2020
AND approved = 1
)
;
Alternatively, you could use a right join. In this case you would just need to move the user_id IN (…) condition, similarly to the LEFT JOIN solution above, and replace the second INNER JOIN with RIGHT JOIN:
SELECT
cc.comment, cc.date_added, u.fullname, u.mainimage_id
FROM
(
SELECT user_id, MAX(comment_id) AS maxcomment
FROM chat_comments
GROUP BY user_id
) a
INNER JOIN
chat_comments cc ON
a.user_id = cc.user_id AND
a.maxcomment = cc.comment_id
RIGHT JOIN
user_details u ON
a.user_id = u.user_id
WHERE u.user_id IN (select user_id2 from chat_friends where user_id=2020 AND approved=1)

How do I use an IF statement in an MySQL join query?

I have a SQL query that left joins a table in different ways depending on a condition.
SELECT m.id, u.first_name AS otherUser
FROM matches AS m
IF (u.id=m.user2ID)
LEFT JOIN users AS u ON u.id = m.user1ID
ELSE
LEFT JOIN users AS u ON u.id = m.user2ID
ENDIF
WHERE m.user1ID=2 OR m.user2ID=2
matches is a table with integer columns user1ID and user2ID. users is a table containing users of my web application. users has a VARCHAR field called first_name.
The intention of this query is to get the names of the users matched with the current user.
However, MySQL returns this error:
#1064 - You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for
the right syntax to use near 'IF (u.id=m.user2ID) LEFT JOIN users
AS u ON u.id = m.user1ID ELSE LEFT JOIN user' at line 3
Why?
Specify the condition as part of the ON clause:
SELECT m.id, u.first_name AS otherUser
FROM matches AS m
LEFT JOIN users AS u ON (u.id=m.user2ID and u.id = m.user1ID) or (u.id<>m.user2ID and u.id = m.user2ID)
WHERE m.user1ID=2 OR m.user2ID=2
Another way to do the same thing:
SELECT m.id, u.first_name AS otherUser
FROM matches AS m
LEFT JOIN users AS u ON IF(u.id=m.user2ID,u.id = m.user1ID,u.id = m.user2ID)
WHERE m.user1ID=2 OR m.user2ID=2
Use this query:
SELECT m.id, u.first_name AS otherUser FROM matches AS m LEFT
JOIN users AS u ON u.id = m.user1ID AND u.id=m.user2ID LEFT JOIN users
AS u1 ON u1.id = m.user2ID WHERE m.user1ID=2 OR m.user2ID=2
Updated query:
SELECT m.id, u.first_name AS otherUser
FROM matches AS m
LEFT JOIN users AS u ON u.id = (CASE WHEN u.id=m.user2ID
THEN m.user1ID
ELSE m.user2ID
END)
WHERE m.user1ID=2 OR m.user2ID=2
Check this Source.
Also check this MYSQL Inner Join if statement . It might be helpful for you.
You can also have two LEFT JOIN on the same table like this...
LEFT JOIN users AS u ON u.id = m.user1ID
LEFT JOIN users AS u2 ON u2.id = m.user2ID
This is an alternative to using IF statements.
You can not use the IF THEN ELSE END IF-stuff in a SELECT in this way. However, you can use it in stored procedures and functions.
I would JOIN u.id with both m.user1ID and m.user2ID and use DISTINCT to avoid duplicates.
There is a IF() which you can use in SELECTs, but you can not do flow control with IF().
Thanks,
It worked for me. Tried something else like below :
**
Create table TEMP1 (ID INT,T_MONTH INT,T_YEAR INT)
INSERT INTO TEMP1 VALUES(1,1,2001)
INSERT INTO TEMP1 VALUES(2,2,2001)
INSERT INTO TEMP1 VALUES(3,3,2001)
**
CREATE TABLE TEMP2 (T_MONTH INT,T_YEAR INT,FREQUENCY CHAR(1),VAL FLOAT)
INSERT INTO TEMP2 VALUES(1,2001,'M',1.1)
INSERT INTO TEMP2 VALUES(3,2001,'M',1.2)
INSERT INTO TEMP2 VALUES(3,2001,'Q',1.3)
INSERT INTO TEMP2 VALUES(12,2001,'A',1.4)
SELECT * FROM TEMP1 L JOIN TEMP2 H
ON L.T_YEAR = H.T_YEAR
OR (L.T_MONTH = (CASE WHEN H.FREQUENCY='M'
THEN H.T_MONTH
END)
OR dbo.GetQuarterFromMonth(L.T_MONTH) = (CASE WHEN H.FREQUENCY = 'Q'
THEN dbo.GetQuarterFromMonth(H.T_MONTH)
END))
WHERE H.FREQUENCY = 'Q'
Here GetQuarterFromMonth is a user defined funtion which returns Quarter for a particular month.
The objective of above query is to inflate the value of Quarter for all the months in table 1. If frequency is annual then in that case the value should be inflated for all the months 1-12 of table 1 which is achieved through first join condition. In case frequency is Monthly then each month from table1 should be mapped to table2. The only unique case is handling quarter frequency.