I need to create a join query between several tables based on the output of some previous table. I am trying to use case when statement as follows but its showing error! any kind of help is appreciated
SELECT completion.userid, completion. coursemoduleid, completion. timemodified,
module.course, user. idnumber as student_id, m.name as module_name, activity.name as activity_name
FROM `mdl_course_modules_completion` as completion
join mdl_course_modules as module
on completion. coursemoduleid = module.id
join mdl_user as user on user.id = completion.userid
join mdl_modules as m on completion. coursemoduleid = m.id
join
CASE WHEN module_name = 'assign'THEN 'mdl_assign'
WHEN module_name = 'assignment' THEN 'mdl_assignment'
ELSE "quiz"
END AS activity
on activity.id = m.id LIMIT 0, 30
There is no such thing as "conditional join". Instead you can use two LEFT JOINs and COALESCE():
SELECT completion.userid,
...
COALESCE(activity1.name, activity2.name) as activity_name -- SELECT first non NULL value
FROM `mdl_course_modules_completion` as completion
...
LEFT JOIN mdl_assign activity1
ON activity1.id = m.id -- JOIN condition
AND module_name = 'assign' -- CASE condition
LEFT JOIN mdl_assignment activity2
ON activity2.id = m.id -- JOIN condition
AND module_name = 'assignment' -- CASE condition
Hope this will help you -
SELECT completion.userid, completion. coursemoduleid, completion. timemodified,
module.course, user. idnumber as student_id, m.name as module_name,(CASE WHEN (a.name != '') THEN a.name ELSE (CASE WHEN (ass.name != '') THEN ass.name ELSE q.name END) END) as activity_name
FROM `mdl_course_modules_completion` as completion
join mdl_course_modules as module
on completion. coursemoduleid = module.id
join mdl_user as user on user.id = completion.userid
join mdl_modules as m on completion. coursemoduleid = m.id
left join mdl_assign as a on a.id = m.id
left join mdl_assignment as ass on ass.id = m.id
left join mdl_quiz as q on q.id = m.id
where m.name in ('assign','assignment','quiz')
LIMIT 0, 30
Related
I have the following 3 tables:
users: [id, name, admin ...]
events: [id, user_id, type ...]
messages: [id, user_id, ...]
I want to construct a query that does the following:
-> Select all users from the table users who have not scheduled an event of the type "collection"
-> And who have less than 3 messages of the type "collection_reminder"
-> And who are not admin
I've managed to figure out the first part of this query, but it all goes a bit pear shaped when I try to add the 3 table, do the count, etc.
Here is a query that might get the job done. Each of the requirement is represented as a condition in the WHERE clause, using correlated subqueries when needed:
SELECT u.*
FROM users u
WHERE
NOT EXISTS (
SELECT 1
FROM events e
WHERE e.user_id = u.id AND e.type = 'collection'
)
AND (
SELECT COUNT(*)
FROM messages m
WHERE m.userid = u.id AND m.type = 'collection_reminder'
) <= 3
AND u.admin IS NULL
Ill try this on the top of the head so expect some synthax issues, but the idea is the following.
You can filter out who have no events schedule using a left join. On a left join the elements on the second part of the query will show up as null.
select * from users u
left join events e on e.user_id = u.id
where e.user_id is null
Now, i dont think this is the most performant way, but a simple way to search for everyone that has 3 or less messages:
select * from users u
left join events e on e.user_id = u.id
where u.id in (
select COUNT(*) from messages m where m.user_id = u.id HAVING COUNT(*)>3;
)
and e.user_id is null
Then filtering who is not admin is the easiest :D
select * from users u
left join events e on e.user_id = u.id
where u.id in (
select COUNT(*) from messages m where m.user_id = u.id HAVING COUNT(*)>3;
)
and e.user_id is null
and u.admin = false
Hope it helps.
This is pretty much a direct translation of your requirements, in the order you listed them:
SELECT u.*
FROM users AS u
WHERE u.user_id NOT IN (SELECT user_id FROM events WHERE event_type = 'Collection')
AND u.user_id IN (
SELECT user_id
FROM messages
WHERE msg_type = 'Collection Reminder'
GROUP BY user_id
HAVING COUNT(*) < 3
)
AND u.admin = 0
or alternatively, this can be accomplished completely with joins:
SELECT u.*
FROM users AS u
LEFT JOIN events AS e ON u.user_id = e.user_id AND e.event_type = 'Collection'
LEFT JOIN messages AS m ON u.user_id = m.user_id AND m.msg_type = 'Collection Reminder'
WHERE u.admin = 0
AND e.event_id IS NULL -- No event of type collection
GROUP BY u.user_id -- Note: you should group on all selected fields, and
-- some configuration of MySQL will require you do so.
HAVING COUNT(DISTINCT m.message_id) < 3 -- Less than 3 collection reminder messages
-- distinct is optional, but
-- if you were to remove the "no event" condition,
-- multiple events could multiply the message count.
;
This query uses joins to link the 3 tables, filters the result using the where clause, and using Group by, having limiting the result to only those who satisfy the less than count condition..
SELECT a.id,
SUM(CASE WHEN b.type = 'collection' THEN 1 ELSE 0 END),
SUM(CASE WHEN c.type = 'collection_reminder' THEN 1 ELSE 0 END
FROM users a
left join events b on (b.user_id = a.id)
left join messages c on (c.user_id = a.id)
WHERE a.admin = false
GROUP BY a.id
HAVING SUM(CASE WHEN b.type = 'collection' THEN 1 ELSE 0 END) = 0
AND SUM(CASE WHEN c.type = 'collection_reminder' THEN 1 ELSE 0 END) < 3
I am working on a query whose purpose is to get the records of all the students whose financialyear_id!=4 and don't dispaly records even if he/she has finacialyear_id other then 4 exist.
I have written a query but it gives me the record of that student whose finacialyear_id!=4 but I want to achieve that no records will be shown if financialyear_id=4 exist for any student.
SELECT a.id aid
, s.id sid
, s.name
, s.father_name
, s.cnic
, f.financialyear_id
FROM student s
JOIN academic_info a
ON a.s_id = s.id
LEFT
JOIN fee_issued f
ON a.id = f.academic_info_id
WHERE f.financialyear_id != 4
AND a.is_data_locked = 0
AND a.university_id = 60;
Foreign Key: s_id in both tables academic_info and fee_issued,academic_info_id in fee_issued table.
You used a keyword in your request: "but I want to achieve that no records will be shown if financialyear_id=4 exist for any student." So use EXISTS (or IN which does about the same) to check for existence.
As you are using MySQL you must write the select condition for academic_info twice. Other DBMS handle this more elegantly.
select a.id as aid, s.id as sid, s.name, s.father_name, s.cnic, f.financialyear_id
from student s
join academic_info a on a.s_id = s.id and a.is_data_locked = 0 and a.university_id = 60
left join fee_issued f on f.academic_info_id = a.id
where s.id not in
(
select ai.s_id
from academic_info ai
join fee_issued fi on fi.academic_info_id = ai.id and fi.financialyear_id != 4
where ai.is_data_locked = 0 and ai.university_id = 60
);
Above query also gets you students that have no fee_issued at all. If you want these removed, change the left join to an inner join.
EDIT: Here is the same with NOT EXISTS.
select a.id as aid, s.id as sid, s.name, s.father_name, s.cnic, f.financialyear_id
from student s
join academic_info a on a.s_id = s.id and a.is_data_locked = 0 and a.university_id = 60
left join fee_issued f on f.academic_info_id = a.id
where not exists
(
select *
from academic_info ai
join fee_issued fi on fi.academic_info_id = ai.id and fi.financialyear_id != 4
where ai.is_data_locked = 0 and ai.university_id = 60
and ai.s_id = s.id
);
select t.* FROM user_tq t join
CASE when t.blogid = 0 then user_dp ELSE user_blog END b
on t.uid = b.uid where ***;
I want to join different table according to blogid, when blogid is 0, join user_dp, else join user_blog.But it returns 1064 error.
How to solve this problem?
You can do this with left join and filter the right result by COALESCE
select t.*
FROM user_tq t
left join user_dp ud on t.blogid = 0 and t.uid = ud.uid
left join user_blog ub on t.blogid != 0 and t.uid = ub.uid
where
COALESCE(ud.uid, ub.uid) IS NOT NULL and
***;
For more info refer : MySQL query where JOIN depends on CASE
If you are trying to inner join to filter data on condition then;
select * from (
select t.*
FROM user_tq t
join user_dp ud on t.blogid = 0 and t.uid = ud.uid
union all
select t.*
FROM user_tq t
join user_blog ub on t.blogid != 0 and t.uid = ub.uid
) as x
where ****;
USE:
select * FROM users t
left join user_role r ON t.user_id = 0 AND r.user_id = t.user_id
left join product_category c ON t.user_id != 0 AND c.user_id = t.user_id
WHERE COALESCE(r.user_id, c.user_id) IS NOT NULL
WHERE ***;
Replace users, user_role and product_category with your tables.
The other answers posted here are the correct solutions.
I'll answer the "Why do I get 1064" for you.
The syntax you've written is invalid. You cannot "conditionally" join to a table like this.
What you can do is LEFT JOIN - which as opposed to [INNER] JOIN means "return NULL for all fields on this table if no record matches the join condition".
There's lots on the Internet about LEFT vs INNER joins, and MySQL's website documents the COALESCE function very well.
Have a play and a read, you'll figure it out why the other solutions work.
Upon reflection, I felt this could benefit from some additional explanation.
See this SQLFiddle: http://sqlfiddle.com/#!9/043b7/6
I have 3 tables say Jobs, results, ordered, I have joined 'jobs' and 'results' table (using jobID ) and I need to check the whether the result ID is present in orders tables or not, if present it should print Yes or else no
set #sno:=0; SELECT #sno:=#sno+1 Id, j.job_id,gr.name as Group_name, u.name User_name, p.name Project_name, j.version,j.type,vendor,tech, functionality as Algo,words,bits,freq, j.status,r.macroId, CASE WHEN o.macroId IS NULL THEN 'No' ELSE 'Yes' END Ordered, j.cmd_line,j.submit_date FROM job j JOIN cut_results_vw r ON j.job_id = r.jobId LEFT OUTER JOIN project p ON j.project_id = p.project_id LEFT OUTER JOIN user u ON j.user_id = u.user_id LEFT OUTER JOIN groups gr ON j.group_id = gr.group_id LEFT JOIN ordered_cuts o ON r.macroId = o.macroId
select j.*,
case when o.resultid is not null
then 'yes'
else 'no'
end as present
from jobs j
inner join results r on r.jobid = j.jobid
left outer join orders o on o.resultid = r.resultid
It's hard to tell without seeing your actual table schemas, but you can try it this way
SELECT j.*, r.*,
CASE WHEN o.resultid IS NULL THEN 'No' ELSE 'Yes' END resultid_is_present
FROM jobs j JOIN results r
ON j.jobid = r.jobid LEFT JOIN ordered o
ON r.resultid = o.resultid
To better understand JOINs read
A Visual Explanation of SQL Joins
I have a table with 3 fields. principal, associate, status.
How can I determine whether the logged-in user is either a principal or an associate, and with how many people he is associated? I would also like to determine the status of the relationship.
query = "SELECT M.id, M.surname, M.firstname, R.principal_id
, R.associate_id, R.status
FROM tbl_members M, tbl_relationship R WHERE
-- ---------------------------------------------
-- to make sure user exists in the members table
-- ---------------------------------------------
(R.principal_id = M.id OR R.associate_id = M.id)
AND (logged-in-user = R.associate_id OR logged-in-user = R.principal_id)
AND R.status =1"
ERROR:- THIS LISTS times 2 of everybody in the relationship table.
Tables invloved:-
tbl_members (id, surname, firstname)
tbl_relationship (id, associate_id[FK tbl_member id], principal_id[FK tbl_member id])
associate_id | principal_id | status
1 3 1
1 4 1
2 1 0
2 3 0
5 1 1
6 1 1
From the above how many people are associated with logged-in-user(1)?
Try:
SELECT
m.id, m.surname, m.firstname,
COUNT(assoc.id) AS relationships_as_associate,
COUNT(princ.id) AS relationships_as_principal
FROM tbl_members m
LEFT JOIN tbl_relationship assoc
ON assoc.associate_id = m.id AND assoc.status = 1
LEFT JOIN tbl_relationship princ
ON princ.principal_id = m.id AND princ.status = 1
WHERE m.id = logged-in-user
GROUP BY m.id
(guessing that relationships with status = 0 can be ignored)
If you only want the number of relationships this user is in (no matter the user's role):
SELECT
m.id, m.surname, m.firstname,
COUNT(rel.id) AS active_relationships
FROM tbl_members m
LEFT JOIN tbl_relationship rel
ON (rel.associate_id = m.id OR rel.principal_id = m.id)
AND rel.status = 1
WHERE m.id = logged-in-user
GROUP BY m.id
EDIT:
According to your comment, this is a query that will get all the users who are in relationship with the logged in user, with their details, and the role they are playing in the relationship (some of them are principals, others are associates):
SELECT m.id, m.firstname, m.surname, temp.role
FROM tbl_members m
JOIN ((SELECT rel.principal_id as id, 'Principal' as role
FROM tbl_relationship rel
WHERE rel.associate_id = logged-in-user
AND rel.status = 1)
UNION
(SELECT rel.associate_id as id, 'Associate' as role
FROM tbl_relationship rel
WHERE rel.principal_id = logged-in-user
AND rel.status = 1)
) as temp
ON temp.id = m.id
I'm still not 100% sure how your system is suppose to work, but this is what I came up with.
Select M.id, surname, firstname, NumPrincipal, NumAssociate, 'Type' =
Case
When NumPrincipal > 0 Then 'Principal'
Else 'Associate'
End
from
(Select * From tbl_members) AS M
Left Join
(Select M.id, COUNT(M.id) 'NumPrincipal' from
tbl_members M inner join tbl_relationship R on M.id = R.principal_id
Group By M.Id) AS P
On M.id = P.id
Left Join
(Select M.id, COUNT(M.id) 'NumAssociate' from
tbl_members M inner join tbl_relationship R on M.id = R.associate_id
Group By M.Id) AS A
On M.id = A.id
Where M.id = logged_in_user_id
The part that still seems weird to me is if they initiate an relationship then they will be a principal, but they can also be an associate in another case, it depends on a specific relationship between two users. My code is just if a user logs in and they have been principal before then they are a principal. Not sure if you want code that is like the current user is looking at a specific relationship they have with another user, find who is principal in that relationship?
Edit: Heres the code to see if the current user is the principal when looking at a single relationship between the current user and another user. This assumes there is only one relationship between two users or you will get multiple records back.
Select *,
'type' =
case
when principal_id = currentUserId then 'Principal'
else 'Associate'
end
from tbl_relationship where
(associate_id = currentUserId or principal_id = currentUserId )
and
(associate_id = OtherUserId or principal_id = OtherUserId )
Edit Again, Here is the number of associates regardless of Principal/Associate:
Select M.id, surname, firstname, NumAssociates
From
tbl_members M
Left Join
(Select id, count(NumAssociate) 'NumAssociates' From
((Select M.id, M.id 'NumAssociate' from
tbl_members M inner join tbl_relationship R on M.id = R.principal_id where status = 1)
Union All
(Select M.id, M.id 'NumAssociate' from
tbl_members M inner join tbl_relationship R on M.id = R.associate_id where status = 1)) AS T
Group By Id) AS N
on M.id = N.Id