sql error using subquery in select and from clause - mysql

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'

Related

Inner join after left join to return null

I want to return every p row, and have null values for u.id and u.first_name if they dont have ROLE_ADMIN. When I perform this query I get empty result. If I use left join instead of inner I get incorrect results. How to filter left join so that If nothing matches I still get returned p rows with null values for u.id and u.first_name?
Note: I added p.id = 13455 at the end just for test purposes.
select u.id, u.first_name, p.id
from sub p
left join oub oj on oj.id = p.sub_id
left join jhi_user u on u.oub_id= oj.id
inner join jhi_user_authority ua on ua.user_id = u.id where ua.authority_name = 'ROLE_ADMIN' and p.id = 13544;
use left join like below
select u.id, u.first_name, p.id
from sub p
left join oub oj on oj.id = p.sub_id
left join jhi_user u on u.oub_id= oj.id
left join
( select * from
jhi_user_authority where authority_name = 'ROLE_ADMIN'
) ua on ua.user_id = u.id
where p.id = 13544;
I think the logic you want is:
select
ua.user_id,
case when ua.user_id is not null then u.first_name end as first_name,
p.id
from sub p
left join oub oj
on oj.id = p.sub_id
left join jhi_user u
on u.oub_id= oj.id
left join jhi_user_authority ua
on ua.user_id = u.id
and ua. authority_name = 'ROLE_ADMIN'
and u.id is not null
So I solved it like this:
select u.id, u.first_name, p.id
from sub p
left join oub oj on oj.id = p.sub_id
left join jhi_user u on u.id =
(select ru.id from jhi_user ru inner join jhi_user_authority rua on rua.user_id = ru.id and rua.authority_name = 'ROLE_ADMIN' where ru.oub_id= oj.id)
where p.id = 18774;

Complex query containing multiple joins is not executing right outer join

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;

Mysql left join 4 possible values

we're running this query in moodle database:
SELECT l.*,
MAX(l.time) as time,cat.id as catid, cat.name as catname,c.id as courseid,
c.fullname as coursename,
m.name as module,
r.revision as revision,
r.name as resourcename,
sco.name as scormname,
glo.name as glossaryname,
qui.name as quizname
FROM {log} l
INNER JOIN {user} u ON l.userid = u.id
INNER JOIN {course} c ON l.course = c.id
INNER JOIN {course_categories} cat ON c.category = cat.id
INNER JOIN {course_modules} cm ON l.cmid = cm.id
INNER JOIN {modules} m ON cm.module = m.id
LEFT JOIN {resource} r ON cm.instance = r.id and l.module = "resource"
LEFT JOIN {scorm} sco ON cm.instance = sco.id and l.module = "scorm"
LEFT JOIN {glossary} glo ON cm.instance = glo.id and l.module = "glossary"
LEFT JOIN {quiz} qui ON cm.instance = qui.id and l.module = "quiz"
WHERE LOWER(l.action) LIKE LOWER(:modaction) COLLATE utf8_bin AND l.userid = :userid
GROUP BY l.cmid
ORDER BY MAX(l.time) DESC
and i would like something like this:
SELECT l.*,
MAX(l.time) as time,cat.id as catid, cat.name as catname,c.id as courseid,
c.fullname as coursename,
m.name as module,
r.revision as revision,
r.name as resourcename
FROM {log} l
INNER JOIN {user} u ON l.userid = u.id
INNER JOIN {course} c ON l.course = c.id
INNER JOIN {course_categories} cat ON c.category = cat.id
INNER JOIN {course_modules} cm ON l.cmid = cm.id
INNER JOIN {modules} m ON cm.module = m.id
INNER JOIN (
SELECT * {resource} re WHERE cm.instance = r.id OR
SELECT * {scorm} sco WHERE cm.instance = sco.id OR
SELECT * {glossary} WHERE ON cm.instance = glo.id OR
SELECT * {quiz} qui WHERE cm.instance = qui.id OR
) as r
WHERE LOWER(l.action) LIKE LOWER(:modaction) COLLATE utf8_bin AND l.userid = :userid
GROUP BY l.cmid
ORDER BY MAX(l.time) DESC
Results return NULL values in "resource" names (resourcename, scormname, glossaryname or quizname) and only one valid "resource" name. I render results depending on if result is not null.
But i would like to avoid "filter" by not null result in resourcename, scormname, glossaryname and quizname using PHP.
Thanks!
Something like this maybe - use a union
SELECT l.cmid,
MAX(l.time) as logtime,
cat.id as catid,
cat.name as catname,
c.id as courseid,
c.fullname as coursename,
mods.module,
mods.revision,
mods.name as modname
FROM mdl_log l
JOIN mdl_user u ON l.userid = u.id
JOIN mdl_course c ON l.course = c.id
JOIN mdl_course_categories cat ON c.category = cat.id
JOIN (
SELECT cm.id AS cmid, m.name AS module, r.name, r.revision
FROM mdl_course_modules cm
JOIN mdl_modules m ON cm.module = m.id AND m.name = 'resource'
JOIN mdl_resource r ON r.id = cm.instance
UNION
SELECT cm.id AS cmid, m.name as modulentype, s.name, NULL AS revision
FROM mdl_course_modules cm
JOIN mdl_modules m ON cm.module = m.id AND m.name = 'scorm'
JOIN mdl_scorm s ON s.id = cm.instance
UNION
SELECT cm.id AS cmid, m.name as modulentype, g.name, NULL AS revision
FROM mdl_course_modules cm
JOIN mdl_modules m ON cm.module = m.id AND m.name = 'glossary'
JOIN mdl_glossary g ON g.id = cm.instance
UNION
SELECT cm.id AS cmid, m.name as modulentype, q.name, NULL AS revision
FROM mdl_course_modules cm
JOIN mdl_modules m ON cm.module = m.id AND m.name = 'quiz'
JOIN mdl_quiz q ON q.id = cm.instance
) mods ON mods.cmid = l.cmid AND mods.module = l.module
WHERE l.module IN ('resource', 'scorm', 'glossary', 'quiz')
GROUP BY l.cmid
ORDER BY 1 DESC

Pass Value to Subselect

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.

MYSQL union with many JOIN

I'm trying to write a query to fetch a listing from 2 (list1,list2)tables with the same columns.
Are there any other way to rewrite this code?
(SELECT r.id as rid, s.title, u.username
FROM list1 r
JOIN drama s ON r.parent_id = s.id
LEFT JOIN image i ON s.image_id = i.id
LEFT JOIN user u ON r.user_id = u.user_id)
UNION ALL
(SELECT r.id as rid, s.title, u.username
FROM list2 r
JOIN movie s ON r.parent_id = s.id
LEFT JOIN image i ON s.image_id = i.id
LEFT JOIN user u ON r.user_id = u.user_id)
ORDER BY rid LIMIT 10
whats wrong if you do this
SELECT r.id as rid, m.title AS movie Title,
d.title as DramaTitle, u.username
FROM list1 r
INNER JOIN movie m ON r.parent_id = m.id
INNER JOIN drama d ON r.parent_id = d.id
LEFT JOIN image i ON s.image_id = i.id
LEFT JOIN user u ON r.user_id = u.user_id
ORDER BY r.id LIMIT 10
SELECT r.id as rid, s.title, u.username
FROM (SELECT l1.id, l1.user_id, l1.parent_id FROM list1 l1
UNION ALL
SELECT l2.id, l2.user_id, l2.parent_id FROM list2 l2) r
INNER JOIN drama s ON r.parent_id = s.id
LEFT JOIN image i ON s.image_id = i.id
LEFT JOIN user u ON r.user_id = u.user_id
ORDER BY rid
LIMIT 10