SQL query with deeper relationship - mysql

Table: user
Columns
- id
- username
- full_name
Table: pet
Columns
- id
- pet_name
- color_id
Table: pet_color
Columns
- id
- color
Table: results
Columns
- id
- user_id_1
- user_id_2
- user_id_3
- pet_id
- date
- some_text
This:
SELECT A.id, B.full_name, C.full_name, D.full_name, E.pet_name, A.date, A.some_text
FROM RESULTS AS A
LEFT OUTER JOIN USER AS B ON A.USER_ID1 = B.ID
LEFT OUTER JOIN USER AS C ON A.USER_ID2 = C.ID
LEFT OUTER JOIN USER AS D ON A.USER_ID3 = D.ID
LEFT OUTER JOIN PET AS E ON A.PET_ID = E.ID
will give me almost everything that I want except 'pet_color.color', but I can not figure it out what should I add to the query to get that too.

SELECT A.id, B.full_name, C.full_name, D.full_name, E.pet_name, A.date, A.some_text, pc.color
FROM RESULTS AS A
LEFT OUTER JOIN USER AS B ON A.USER_ID1 = B.ID
LEFT OUTER JOIN USER AS C ON A.USER_ID2 = C.ID
LEFT OUTER JOIN USER AS D ON A.USER_ID3 = D.ID
LEFT OUTER JOIN PET AS E ON A.PET_ID = E.ID
LEFT OUTER JOIN PET_COLOR PC on E.color_id = pc.id

SELECT A.id, B.full_name, C.full_name, D.full_name, E.pet_name, A.date, A.some_text, PC.color
FROM RESULTS AS A
LEFT OUTER JOIN USER AS B ON A.USER_ID1 = B.ID
LEFT OUTER JOIN USER AS C ON A.USER_ID2 = C.ID
LEFT OUTER JOIN USER AS D ON A.USER_ID3 = D.ID
LEFT OUTER JOIN PET AS E ON A.PET_ID = E.ID
LEFT OUTER JOIN PET_COLOR PC ON E.COLOR_ID = PC.ID

Not tried, but this should work
SELECT A.id, B.full_name, C.full_name, D.full_name, E.pet_name, A.date, A.some_text
FROM RESULTS AS A
LEFT OUTER JOIN USER AS B ON A.USER_ID1 = B.ID
LEFT OUTER JOIN USER AS C ON A.USER_ID2 = C.ID
LEFT OUTER JOIN USER AS D ON A.USER_ID3 = D.ID
LEFT OUTER JOIN PET AS E ON A.PET_ID = E.ID
INNER JOIN PET_COLOR PC ON PC.ID = E.COLOR_ID

Related

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 query table joins gives duplicate rows

I have the tables movie, movie_client, language_movie, language, subtitle_movie and subtitle
I want to select all movies with their subtitle and language where client_id (in movie_client) is 1
SELECT * FROM movie
LEFT OUTER JOIN movie_client
ON movie.movie_id = movie_client.movie_client_id
LEFT OUTER JOIN client
ON movie_client.client_movie_id = client.client_id
LEFT OUTER JOIN language_movie
ON movie.movie_id = language_movie.movie_id
LEFT OUTER JOIN language
ON language_movie.language_id = language.language_id
LEFT OUTER JOIN subtitle_movie
ON movie.movie_id = subtitle_movie.movie_id
LEFT OUTER JOIN subtitle
ON subtitle_movie.subtitle_id = subtitle.subtitle_id
WHERE client.client_id=1
this does nog work cause i get duplicate rows i tried inner joins as swell but it just wont work. Can anyone help me with the right query?
Give it a try :
SELECT distinct m.movie_id, lm.language_id, sm.subtitle_id FROM movie m
INNER JOIN movie_client mc
ON m.movie_id = mc.movie_client_id
INNER JOIN client
ON mc.client_movie_id = c.client_id
INNER JOIN lm
ON m.movie_id = lm.movie_id
INNER JOIN language l
ON lm.language_id = l.language_id
INNER JOIN subtitle_movie sm
ON m.movie_id = sm.movie_id
INNER JOIN JOIN subtitle s
ON sm.subtitle_id = s.subtitle_id
WHERE client.client_id=1
This
FROM movie
LEFT OUTER JOIN movie_client
ON movie.movie_id = movie_client.movie_client_id
LEFT OUTER JOIN client
ON movie_client.client_movie_id = client.client_id
should be INNER JOINs you don't need all movies
SELECT * FROM movie
INNER JOIN movie_client
ON movie.movie_id = movie_client.movie_client_id
INNER JOIN client
ON movie_client.client_movie_id = client.client_id
LEFT OUTER JOIN language_movie
ON movie.movie_id = language_movie.movie_id
LEFT OUTER JOIN language
ON language_movie.language_id = language.language_id
LEFT OUTER JOIN subtitle_movie
ON movie.movie_id = subtitle_movie.movie_id
LEFT OUTER JOIN subtitle
ON subtitle_movie.subtitle_id = subtitle.subtitle_id
WHERE client.client_id=1
Check this to understand difference INNER and OUTER JOIN

Returning a specific type of entry in a table (SQL)

I have three tables Buildings, EnergyType and EnergyCategory. The first two are connected by a bridge table called build_types. The second two are connected by having related IDs (type_ID = cat_ID).
This join outputs buildings and every energy type they use:
SELECT B.building, E.energytype
FROM Buildings b
INNER JOIN build_types bt ON B.build_ID = bt.build_ID
INNER JOIN EnergyTypes e ON bt.type_ID = E.type_ID
ORDER BY B.building;
This join outputs the total number count of each energy type:
SELECT E.energytype, COUNT(*)
FROM Buildings b
LEFT JOIN build_types bt ON B.build_ID = bt.build_ID
LEFT JOIN EnergyTypes e ON bt.type_ID = E.type_ID
GROUP BY E.energytype;
I want a select statement that will return a table with building name on the left and energy category on the right, with only categories described that are 'Renewable'. I have:
SELECT B.building, E.energytype, E.energycategory
FROM Buildings b
INNER JOIN build_types bt ON B.build_ID = bt.build_ID
INNER JOIN EnergyTypes e ON bt.type_ID = E.type_ID
INNER JOIN EnergyCategories e ON E.cat_ID = E.type_ID
WHERE E.energycategory = 'Renewable';
but I get Error 1066: Not unique table/alias 'EnergyTypes'.
You have chosen the alias "E" for both EnergyTypes and EnergyCategories.
SELECT B.building, T.energytype, C.energycategory
FROM Buildings b
INNER JOIN build_types bt ON B.build_ID = bt.build_ID
INNER JOIN EnergyTypes T ON bt.type_ID = T.type_ID
INNER JOIN EnergyCategories C ON C.cat_ID = T.type_ID
WHERE C.energycategory = 'Renewable';
should work.
Change the alias for one of the tables. Make 'e' something else for one of them.

Mysql query help. I need to make sure atleast one record is returning

I have a query that I know it should atleast return one row. How can i modify my follow query to make sure that album returns data. thanks for any help.
Query Here. I know that Album has a row and I need to return it.
select distinct p.*,
a.ID as parentalbumid,a.CreatorID as albumcreatorid,a.AlbumName,a.AlbumDescription,a.AlbumDefaultImageURL,a.Private,a.DateCreated,a.AdultContent,a.PasswordProtected,a.AllowTags,a.TypeID,a.AlbumAutoID,
mainuser.Username as mainuserusername,mainuser.ID as mainuserid,mainuser.PictureUrl as mainuserpictureurl,
c.ID as commentID,c.PhotoID as commentphotoid,c.OutputMessage,c.CommentDate,
t.ID as tagID,t.PhotoID as tagphotoid,t.UserID,t.TextTag,t.LeftLocation,t.TopLocation,
u.ID as userid,u.Username,u.FirstName,u.LastName,u.PictureUrl
from photos p
inner join albums a on a.ID = p.AlbumID
inner join users mainuser on mainuser.ID = p.UserID
left join comments c on c.PhotoID = p.ID
left join tags t on t.PhotoID = p.ID
left join users u on u.ID = c.CommentBy
where a.AlbumAutoID = 3
order by p.DateUploaded desc;
Use only LEFT JOINs (and put the table albums as the first table of your FROM):
select distinct p.*,
a.ID as parentalbumid,a.CreatorID as albumcreatorid,a.AlbumName,a.AlbumDescription,a.AlbumDefaultImageURL,a.Private,a.DateCreated,a.AdultContent,a.PasswordProtected,a.AllowTags,a.TypeID,a.AlbumAutoID,
mainuser.Username as mainuserusername,mainuser.ID as mainuserid,mainuser.PictureUrl as mainuserpictureurl,
c.ID as commentID,c.PhotoID as commentphotoid,c.OutputMessage,c.CommentDate,
t.ID as tagID,t.PhotoID as tagphotoid,t.UserID,t.TextTag,t.LeftLocation,t.TopLocation,
u.ID as userid,u.Username,u.FirstName,u.LastName,u.PictureUrl
from albums a
left join photos p on a.ID = p.AlbumID
left join users mainuser on mainuser.ID = p.UserID
left join comments c on c.PhotoID = p.ID
left join tags t on t.PhotoID = p.ID
left join users u on u.ID = c.CommentBy
where a.AlbumAutoID = 3
order by p.DateUploaded desc;

Need help with SQL query

Current query
SELECT *
FROM employee AS E
INNER JOIN credential AS C ON (C.id = E.credentialId)
LEFT JOIN person AS P ON (C.personId = P.id)
I want to modify this query so that it I just SELECT the employees/credentials which have both loginroles 1 and 2 (loginrole.id).
Relevant tables
loginrole
id
name
credential_has_loginrole
id
credentialId
loginroleId
You can join a subquery, which will return the credential Id's that have both login roles.
SELECT E.*, C.*, P.*
FROM employee AS E
INNER JOIN (
SELECT credentialId
FROM credential_has_loginrole
WHERE loginroleId IN (1,2)
GROUP BY credentialId
HAVING COUNT(DISTINCT loginroleId) = 2
) g ON E.credentialId = g.credentialId
INNER JOIN credential AS C ON (C.id = E.credentialId)
LEFT JOIN person AS P ON (C.personId = P.id)
Update: As per comments, to find employees with either or:
SELECT E.*, C.*, P.*
FROM employee AS E
INNER JOIN (
SELECT credentialId
FROM credential_has_loginrole
WHERE loginroleId IN (1,2)
GROUP BY credentialId
) g ON E.credentialId = g.credentialId
INNER JOIN credential AS C ON (C.id = E.credentialId)
LEFT JOIN person AS P ON (C.personId = P.id)
Alternatively, you can use a JOIN together with DISTINCT:
SELECT DISTINCT E.*, C.*, P.*
FROM employee AS E
INNER JOIN credential AS C ON (C.id = E.credentialId)
INNER JOIN credential_has_loginrole chr
ON E.credentialId = chr.credentialId
AND chr.loginroleId IN (1,2)
LEFT JOIN person AS P ON (C.personId = P.id)
The Scrum Meister's answer is correct. You can alternatively use 2 join trees:
SELECT *
FROM employee AS E
INNER JOIN credential AS c
INNER JOIN credential_has_loginrole chl0 ON (c0.id=chl0.credentialId AND chl0.loginroleId=1)
INNER JOIN credential_has_loginrole chl1 ON (c0.id=chl1.credentialId AND chl1.loginroleId=2)
ON (c.id = E.credentialId)