I'm writing a query with multiple joins where I want every user to show entries against all category Types. When I execute the query below only 1 record is returned because the employee u.employee_id = "0079-P" has only worked on 1 project but I want to get data for all the category_types with users workhours displayed as null for the categories he didn't work on.
Select u.employee_id As Employee_ID, u.user_name As UserName, COALESCE(primaryDept.ctd_name, primaryProj.ctd_name) As PrimaryDeptOrProj, region.region_name As Region, categoryType.ctd_id, categoryType.ctd_name, SUM(tsdd.workhours)
From users u
LEFT JOIN category_type_details primaryDept ON u.user_primary_department = primaryDept.ctd_id
LEFT JOIN category_type_details primaryProj ON u.user_primary_project = primaryProj.ctd_id
LEFT JOIN regions region ON u.region_id = region.region_id
LEFT JOIN timesheets ts ON u.user_id = ts.timesheet_user
INNER JOIN timesheet_mr tsmr ON ts.timesheet_caller = tsmr.tsmr_id
INNER JOIN timesheet_details tsd ON ts.timesheet_id = tsd.tsd_timesheet_id
INNER JOIN timesheet_day_details tsdd ON tsd.tsd_id = tsdd.tsd_id
RIGHT OUTER JOIN category_type_details categoryType ON tsd.tsd_category_type_id = categoryType.ctd_id
WHERE tsmr.tsmr_id = 14 and u.employee_id = "0079-P"
GROUP BY u.user_id, tsd.tsd_category_type_id;
I tried this query with variations and it returns 1 record in any case.
You could change your query to this:
SELECT u.employee_id AS Employee_ID, u.user_name AS UserName,
COALESCE(pd.ctd_name, pp.ctd_name) AS PrimaryDeptOrProj,
r.region_name AS Region, ct.ctd_id, ct.ctd_name, SUM(tsdd.workhours)
FROM users u
LEFT JOIN category_type_details pd ON u.user_primary_department = pd.ctd_id
LEFT JOIN category_type_details pp ON u.user_primary_project = pp.ctd_id
LEFT JOIN regions r ON u.region_id = r.region_id
LEFT JOIN timesheets ts ON u.user_id = ts.timesheet_user
INNER JOIN timesheet_mr tsmr ON ts.timesheet_caller = tsmr.tsmr_id AND tsmr.tsmr_id = 14
INNER JOIN timesheet_details tsd ON ts.timesheet_id = tsd.tsd_timesheet_id
INNER JOIN timesheet_day_details tsdd ON tsd.tsd_id = tsdd.tsd_id
RIGHT OUTER JOIN category_type_details ct ON tsd.tsd_category_type_id = ct.ctd_id AND u.employee_id = "0079-P"
GROUP BY ct.ctd_id, u.user_id, u.employee_id, u.user_name,
COALESCE(pd.ctd_name, pp.ctd_name), r.region_name, ct.ctd_name
ORDER BY ct.ctd_id, u.user_id, u.employee_id, u.user_name,
COALESCE(pd.ctd_name, pp.ctd_name), r.region_name, ct.ctd_name;
You only got 1 row because the condition in WHERE clause filter all the NULL user_id rows for other category.
For MySQL, you could omit other columns in GROUP BY clause:
SELECT u.employee_id AS Employee_ID, u.user_name AS UserName,
COALESCE(pd.ctd_name, pp.ctd_name) AS PrimaryDeptOrProj,
r.region_name AS Region, ct.ctd_id, ct.ctd_name, SUM(tsdd.workhours)
FROM users u
LEFT JOIN category_type_details pd ON u.user_primary_department = pd.ctd_id
LEFT JOIN category_type_details pp ON u.user_primary_project = pp.ctd_id
LEFT JOIN regions r ON u.region_id = r.region_id
LEFT JOIN timesheets ts ON u.user_id = ts.timesheet_user
INNER JOIN timesheet_mr tsmr ON ts.timesheet_caller = tsmr.tsmr_id AND tsmr.tsmr_id = 14
INNER JOIN timesheet_details tsd ON ts.timesheet_id = tsd.tsd_timesheet_id
INNER JOIN timesheet_day_details tsdd ON tsd.tsd_id = tsdd.tsd_id
RIGHT OUTER JOIN category_type_details ct ON tsd.tsd_category_type_id = ct.ctd_id AND u.employee_id = "0079-P"
GROUP BY ct.ctd_id, u.user_id
ORDER BY ct.ctd_id, u.user_id;
Related
I get error When I use subquery in select and from clause
Error: https://www.awesomescreenshot.com/image/3069216/0505cad495528e9f9af2281ea281415c.
Here what I have done so far:
SELECT m.id, m.title_name, m.release_date, m.plot, m.poster,
(SELECT count(*) FROM users_ratings WHERE type_id = m.id AND type_name = 'movies' LIMIT 1) count_user_rating
FROM (SELECT u.* FROM users u
LEFT JOIN users_ratings ur ON ur.user_id = u.id
WHERE ur.type_id = 2
AND ur.type_name = 'movies') u
LEFT JOIN users_ratings ur ON ur.user_id = u.id
LEFT JOIN movies m ON m.id = ur.type_id
WHERE ur.type_name = 'movies'
UNION
SELECT s.id, s.title_name, s.first_air_date release_date, s.plot, s.poster,
(SELECT count(*) FROM users_ratings WHERE type_id = s.id AND type_name = 'series' LIMIT 1) count_user_rating
FROM (SELECT u.* FROM users u
LEFT JOIN users_ratings ur ON ur.user_id = u.id
WHERE ur.type_id = 2
AND ur.type_name = 'movies') u
LEFT JOIN users_ratings ur ON ur.user_id = u.id
LEFT JOIN series s ON s.id = ur.type_id
WHERE ur.type_name = 'series'
Not sure whats wrong in your query, seems fine to me. But here is another way to achieve it. Try this
SELECT m.id,
m.title_name,
m.release_date,
m.plot,
m.poster,
t.count_user_rating
FROM (SELECT u.*
FROM users u
LEFT JOIN users_ratings ur
ON ur.user_id = u.id
WHERE ur.type_id = 2
AND ur.type_name = 'movies') u
LEFT JOIN users_ratings ur
ON ur.user_id = u.id
LEFT JOIN movies m
ON m.id = ur.type_id
LEFT JOIN (SELECT type_id,
Count(*) AS count_user_rating
FROM users_ratings
WHERE NAME = 'movies'
GROUP BY type_id) t
ON t.type_id = m.id
WHERE ur.type_name = 'movies'
UNION
SELECT s.id,
s.title_name,
s.first_air_date release_date,
s.plot,
s.poster,
t.count_user_rating
FROM (SELECT u.*
FROM users u
LEFT JOIN users_ratings ur
ON ur.user_id = u.id
WHERE ur.type_id = 2
AND ur.type_name = 'movies') u
LEFT JOIN users_ratings ur
ON ur.user_id = u.id
LEFT JOIN series s
ON s.id = ur.type_id
LEFT JOIN (SELECT type_id,
Count(*) AS count_user_rating
FROM users_ratings
WHERE NAME = 'series'
GROUP BY type_id) t
ON t.type_id = s.id
WHERE ur.type_name = 'series'
I am trying to do a left outer join to a subquery, is that possible?
Can I do something like this?:
##this is this weeks targets
select * from targets t
inner join streams s on s.id = t.stream_id
where t.week_no =WEEKOFYEAR(NOW())
left outer join
(
###############This is records selected so far this week
select p.brand_id, p.part_product_family, sum(r.best) from records r
inner join products p on p.id = r.product_id
left outer join streams s on s.body = p.brand_id and s.stream = p.part_product_family
where WEEKOFYEAR(r.date_selected) =WEEKOFYEAR(NOW())
group by p.brand_id, p.part_product_family;
) sq_2
on s.stream = sq_2.part_product_family
This is working:
##this is this weeks targets
select * from targets t
inner join streams s on s.id = t.stream_id
left outer join
(
###############This is records selected so far this week
select p.brand_id, p.part_product_family, sum(r.best) from records r
inner join products p on p.id = r.product_id
left outer join streams s on s.body = p.brand_id and s.stream = p.part_product_family
where WEEKOFYEAR(r.date_selected) =WEEKOFYEAR(NOW()) and YEAR(r.date_selected) = YEAR(now())
group by p.brand_id, p.part_product_family
) sq_2
on s.body = sq_2.brand_id and s.stream = sq_2.part_product_family
I have an mysql query for getting which user assigned to which course and if the course having certificate then only the results will be prints. for this i am using inner join with many table. Here is the code :
SELECT DISTINCT c.fullname,usr.id, usr.username, usr.email, c.enrolenddate
FROM m_tl_course AS c
INNER JOIN m_tl_context AS cx ON c.id = cx.instanceid AND cx.contextlevel = '50'
INNER JOIN m_tl_role_assignments AS ra ON cx.id = ra.contextid
INNER JOIN m_tl_role AS r ON ra.roleid = r.id
INNER JOIN m_tl_user AS usr ON ra.userid = usr.id
INNER JOIN m_tl_certificate AS ce ON ce.course = c.id
WHERE r.name = "Student" and ra.timeend = '0'
I have an another table to having data's like the user's who's download their certificate. The table name is m_tl_certification.
In this table having Columns like, user_id ( this the user id), Course_id (this is the course id), cert_date ( this is the certificate download date).
What i want is i want to get the user's who is not download their certicate.
How to get this. please can anyone help me ?
What will be the column value if not downloaded and if downloaded. If the Download date is NULL then in where add Download_Date IS NULL
SELECT DISTINCT c.fullname,usr.id, usr.username, usr.email,c.enrolenddate
FROM m_tl_course AS c
INNER JOIN m_tl_context AS cx ON c.id = cx.instanceid AND cx.contextlevel = '50'
INNER JOIN m_tl_role_assignments AS ra ON cx.id = ra.contextid
INNER JOIN m_tl_role AS r ON ra.roleid = r.id
INNER JOIN m_tl_user AS usr ON ra.userid = usr.id
INNER JOIN m_tl_certificate AS ce ON ce.course = c.id INNER JOIN m_tl_certificate AS ce ON ce.course = c.id
INNER JOIN m_tl_certification As cee ON cee.user_id = usr.id
WHERE r.name = "Student" and ra.timeend = '0' and cee.downloadDate IS NULL
Modify your query with the following
SELECT DISTINCT c.fullname,usr.id, usr.username, usr.email, c.enrolenddate
FROM m_tl_course AS c
INNER JOIN m_tl_context AS cx ON c.id = cx.instanceid AND cx.contextlevel = '50'
INNER JOIN m_tl_role_assignments AS ra ON cx.id = ra.contextid
INNER JOIN m_tl_role AS r ON ra.roleid = r.id
INNER JOIN m_tl_user AS usr ON ra.userid = usr.id
LEFT JOIN m_tl_certificate AS ce ON ce.course = c.id
WHERE r.name = "Student" and ra.timeend = '0'
SELECT
u.*,
GROUP_CONCAT(DISTINCT f.shot_id SEPARATOR ",") AS ownFavorites,
GROUP_CONCAT(DISTINCT st.shot_id SEPARATOR ",") AS ownStars,
GROUP_CONCAT(DISTINCT s.id SEPARATOR ",") AS ownShots,
( SELECT AVG(p.count)
FROM points p
LEFT JOIN shots s ON s.user_id = **U.ID** AND p.shot_id = s.id
WHERE date >= DATE_SUB(CURDATE(),INTERVAL 2 DAY)
) AS attention,
( SELECT SUM(p.count)
FROM points p
LEFT JOIN shots s ON s.user_id = **U.ID** AND s.id = p.shot_id
) AS popularity
FROM users u
LEFT OUTER JOIN shots s ON s.user_id = u.id
LEFT OUTER JOIN favorites f ON f.user_id = u.id
LEFT OUTER JOIN stars st ON st.user_id = u.id
WHERE u.username = ?;
I got two subselects which use the parameter u.id (marked in the query). If i do the sql like this it will generate somthing like that:
#1054 - Unknown column 'u.id' in 'on clause'
Means, the u.id id is NOT defined in the SubSelects. But in the MainSelect I choose from the users table, where u.id exists.
To my question: Is there a way to pass the selected u.id value to the Subselects with common sql?
Don't forget GROUP BY in the subqueries:
SELECT
u.*,
COALECSE(a.average, 0) attention,
COALESCE(p.total, 0) popular,
GROUP_CONCAT(DISTINCT f.shot_id) AS ownFavorites,
GROUP_CONCAT(DISTINCT st.shot_id SEPARATOR ",") AS ownStars,
GROUP_CONCAT(DISTINCT s.id SEPARATOR ",") AS ownShots
FROM
users u
LEFT JOIN
(
SELECT
s.user_id,
AVG(p.count) average
FROM
shots s
JOIN
points p
ON s.id = p.shot_id
WHERE
s.date >+ CURRENT_DATE - INTERVAL 2 DAY
GROUP BY s.user_id
) a
ON u.id = a.user_id
LEFT JOIN
(
SELECT
s.user_id,
SUM(p.count) total
FROM
shots s
JOIN
points p
ON s.id = p.shot_id
GROUP BY s.user_id
) p
ON u.id = p.user_id
LEFT OUTER JOIN shots s ON s.user_id = u.id
LEFT OUTER JOIN favorites f ON f.user_id = u.id
LEFT OUTER JOIN stars st ON st.user_id = u.id
WHERE u.username = 'user'
Seems like this may work. The select doesn't have knowledge of the of the users table the way you had it. I believe this would have knowledge of Users.
SELECT
u.*,
GROUP_CONCAT(DISTINCT f.shot_id SEPARATOR ",") AS ownFavorites,
GROUP_CONCAT(DISTINCT st.shot_id SEPARATOR ",") AS ownStars,
GROUP_CONCAT(DISTINCT s.id SEPARATOR ",") AS ownShots,
A.Attention, P.Popularity
FROM users u
LEFT OUTER JOIN shots s ON s.user_id = u.id
LEFT OUTER JOIN favorites f ON f.user_id = u.id
LEFT OUTER JOIN stars st ON st.user_id = u.id
LEFT OUTER JOIN
( SELECT AVG(p.count) attention
FROM points p
LEFT JOIN shots s ON s.user_id = **U.ID** AND p.shot_id = s.id
WHERE date >= DATE_SUB(CURDATE(),INTERVAL 2 DAY)
) AS A,
( SELECT SUM(p.count) popularity
FROM points p
LEFT JOIN shots s ON s.user_id = **U.ID** AND s.id = p.shot_id
) AS P
WHERE u.username = ?;
Try turning the selects into a subselect join.
FROM users u
LEFT OUTER JOIN shots s ON s.user_id = u.id
LEFT OUTER JOIN favorites f ON f.user_id = u.id
LEFT OUTER JOIN stars st ON st.user_id = u.id
LEFT OUTER JOIN ( SELECT AVG(p.count) AverageOfP, p.shot_id
FROM points p
WHERE date >= DATE_SUB(CURDATE(),INTERVAL 2 DAY)
) p ON p.shot_id = s.id
LEFT OUTER JOIN ( SELECT SUM(p.count) SumOfP, p.shot_id
FROM points p
) p2 ON p2.shot_id = s.id
The s table is already joined to u and should be good. Then in your select you can just select AverageOfP and SumOfP.
SELECT s.*,
u.username,
u.fullname,
c.title AS ctitle,
c.description AS cdescription,
sa.attention,
sp.popularity,
COUNT(DISTINCT f.id) AS favorites,
COUNT(DISTINCT st.id) AS stars,
COUNT(DISTINCT v.id) AS views
FROM shots s
INNER JOIN users u ON u.id = s.user_id
INNER JOIN categories c ON c.id = s.cat_id
LEFT OUTER JOIN(
SELECT shot_id, round(AVG(count),2) AS attention
FROM points
WHERE date > DATE_SUB(CURDATE(),INTERVAL 2 DAY)
GROUP BY shot_id
) sa ON sa.shot_id = s.id
LEFT OUTER JOIN(
SELECT shot_id, SUM(count) AS popularity
FROM points
GROUP BY shot_id
) sp ON sp.shot_id = s.id
LEFT OUTER JOIN favorites f ON f.shot_id = s.id
LEFT OUTER JOIN stars st ON st.shot_id = s.id
LEFT OUTER JOIN views v ON v.shot_id = s.id
**WHERE s.library = 1 AND sa.attention > 40
ORDER BY sa.attention DESC
LIMIT 0,50**
GROUP BY s.id
I can't use the sa.attention in a condition and for ordering. Why?
(I removed the marked part, and the query works!)
What do I have to change in my Query? And if you could give a explanation for it, that would be very nice!
You are negating your OUTER JOIN by putting that in your WHERE criteria. Move it to your JOIN and you'll get your NULL records back:
SELECT s.*,
u.username,
u.fullname,
c.title AS ctitle,
c.description AS cdescription,
sa.attention,
sp.popularity,
COUNT(DISTINCT f.id) AS favorites,
COUNT(DISTINCT st.id) AS stars,
COUNT(DISTINCT v.id) AS views
FROM shots s
INNER JOIN users u ON u.id = s.user_id
INNER JOIN categories c ON c.id = s.cat_id
LEFT OUTER JOIN(
SELECT shot_id, round(AVG(count),2) AS attention
FROM points
WHERE date > DATE_SUB(CURDATE(),INTERVAL 2 DAY)
GROUP BY shot_id
) sa ON sa.shot_id = s.id AND sa.attention > 40
LEFT OUTER JOIN(
SELECT shot_id, SUM(count) AS popularity
FROM points
GROUP BY shot_id
) sp ON sp.shot_id = s.id
LEFT OUTER JOIN favorites f ON f.shot_id = s.id
LEFT OUTER JOIN stars st ON st.shot_id = s.id
LEFT OUTER JOIN views v ON v.shot_id = s.id
WHERE s.library = 1
GROUP BY s.id
ORDER BY sa.attention DESC
LIMIT 0,50
A second note, GROUP BY cannot go at the end. I moved that to the correct spot as well.