How to get rating for each user? - mysql

i have a such type of relations in db.
I wrote such SQL code to get list of user with their average rating.
SELECT
c.id,l.login,
AVG(f.mark) AS AVGRating
FROM logininfo l
INNER JOIN person p
ON l.id = p.info_id
JOIN candidate c
ON p.id = c.id
JOIN feedback f
GROUP BY c.id
ORDER BY AVGRating ASC;
Problem is that I get same rating for all users.

You missed the join condition for the feedback table:
SELECT
c.id,l.login,
AVG(f.mark) AS AVGRating
FROM logininfo l
JOIN person p
ON l.id = p.info_id
JOIN candidate c
ON p.id = c.id
JOIN feedback f
ON c.id = f.candidat_id -- < -- this one
GROUP BY c.id
ORDER BY AVGRating ASC;
Btw, INNER JOIN and JOIN are the same.

SELECT
c.id,l.login,
AVG(f.mark) AS AVGRating
FROM logininfo l
INNER JOIN person p
ON l.id = p.info_id
JOIN candidate c
ON p.id = c.id
JOIN feedback f
--add a join condition
GROUP BY c.id
ORDER BY AVGRating ASC;

Related

Convert query with exists to joins

I want to convert this query in such a way so it does not have any 'exists' and uses only simple joins.
select t.Teacher_id, t.Teacher_name, a.marks, a.grade_ID
from Grades a
left join students s on a.student_ID = s.student_ID
left join Teachers t on t.Teacher_ID = s.Teacher_ID
where 1=1 and t.Teacher_id = 1807600
and exists(
select p.Payment_ID from payments p
inner join lookups l on (l.lookup_id = p.status_id and l.lookup_key in ('condition1','condition2'))
where p.student_ID = a.student_ID
)
I tried something like:
select t.Teacher_id, t.Teacher_name, a.marks, a.grade_ID
from Grades a
left join students s on a.student_ID = s.student_ID
left join Teachers t on t.Teacher_ID = s.Teacher_ID
inner join payments p on p.student_ID = a.student_ID
inner join lookups l on (l.lookup_id = p.status_id and l.lookup_key in ('condition1','condition2'))
where 1=1 and t.Teacher_id = 1807600
But I'm not getting the right results. Can you please help. Thanks.
I suppose you could use group by, but this restricts the maintainability of the script for the simple sake of not using EXISTS().
select t.Teacher_id, t.Teacher_name, a.marks, a.grade_ID
from Grades a
left join students s on a.student_ID = s.student_ID
left join Teachers t on t.Teacher_ID = s.Teacher_ID
inner join payments p on p.student_ID = a.student_ID
inner join lookups l on (l.lookup_id = p.status_id and l.lookup_key in ('condition1','condition2'))
where t.Teacher_id = 1807600
group by t.Teacher_id, t.Teacher_name, a.marks, a.grade_ID

Get only those rows where column a has as many duplicate entries, as many there is distinctive values in column b

My current query:
select users.id as user_id, opportunities.id as op_id, opportunities.title, certificates.id as cert_id from opportunities
join opportunity_certificates on opportunities.id=opportunity_certificates.opportunity_id
join certificates on opportunity_certificates.certificate_id=certificates.id
join user_certificates on certificates.id=user_certificates.certificate_id
join users on user_certificates.user_id=users.id
where opportunity_certificates.is_required = 1 and
opportunities.id = 1
This produces the table on the picture below.
cert_id column can have values from 1 to 7, depends on the opportunities.id. In the table below, I want the query to return only the rows which have the same user_id but different cert_id, 1 and 2.
If the table had 3 different cert_id, I would want it to return only the rows which have same user_id but different cert_id, 1,2 and 3.
when the cert_id has only one value, query should return all the records with that one value in cert_id. Basically, it should show all users who have all required certificates.
The query has to be in the current format. I experimented with
group by users.id
having count(*) >
but I don't know how to make that comparison dynamic, relative to the count of distinctive values in the cert_id column.
Compare counts with a having condition.
select u.id as user_id --, o.id as op_id, o.title
from opportunities o
join opportunity_certificates oc on o.id=oc.opportunity_id
join certificates c on oc.certificate_id=c.id
join user_certificates uc on c.id=uc.certificate_id
join users u on uc.user_id=u.id
where oc.is_required = 1 and o.id = 1
group by u.id --,o.id,o.title
having count(distinct c.id)=(select count(distinct id) from certificates)
Useful?
with data as (
select users.id as user_id, o.title, c.id as cert_id
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
)
select user_id, min(title) as title, max(cert_id) as num_certs
from data
group by user_id
having count(cert_id) = (select max(cert_id) from data);
I'm assuming that cert_id values start and 1 and run sequentially. You could also use count(distinct ...) in the having clause but it guess it's debatable which ones expresses you intent more clearly.
If your version of MySQL doesn't support CTEs then you should be able to just drop that whole subquery into the having clause as well.
select u.id as user_id, min(o.title) as title, max(c.cert_id) as num_certs
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
group by u.id
having count(c.cert_id) = (
select max(c.cert_id)
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
);
Here's another one that might work if you have window functions available. (It might work with Laravel better?):
select *
from (
select users.id as user_id, o.title,
count(distinct c.id) over (partition by u.id) as user_certs,
max(c.id) over () as total_certs
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
) t
where user_certs = total_certs;

MySQL Selecting from multiple rows

Using MySQL I am trying to pull ALL people who's company_id matches 3 and also compare whether that person exists in the favourites table.
What I have noticed is that if a person has no job_id then they are not output by the below query.
The below query outputs 1 row, but in the people table there are 3 rows that match the company_id of 3
SELECT *,
j.company_id as companyid,
f.id IS NOT NULL AS jid,
p.id as pid,
f.id AS fave_id,
f.id IS NOT NULL AS fave
FROM people p
INNER JOIN job j
ON p.job_id = j.id
LEFT JOIN favourites f
ON f.people_id=p.id
AND f.user_id = 12
WHERE p.company_id = 3
ORDER BY p.id ASC
SQLFiddle
Any help is appreciated to get the query to output all rows that match and also check the favourites table.
If you put a left join on job, it will show people that have no job_id. I have updated the fiddle here.
SELECT
p.*,
j.company_id as companyid,
f.id IS NOT NULL AS jid,
p.id as pid,
f.id AS fave_id,
f.id IS NOT NULL AS fave
FROM people p
LEFT JOIN job j
ON j.id = p.job_id
LEFT JOIN favourites f
ON f.people_id=p.id
AND f.user_id = 12
WHERE p.company_id = 3
ORDER BY p.id ASC
You should change your INNER JOIN for the job table to a LEFT OUTER JOIN so they're selected regardless of whether or not they exist in the job table.

Selecting All Rows in SQL, With Specific Criteria

I have a fairly complicated SQL statement I am working on. Here is where I am at:
SELECT c.category
FROM master_cat as c
LEFT JOIN
(
SELECT cat_id, user_id COUNT(cat_id) favoriteCat
FROM ratings
GROUP BY user_id
) a ON a.cat_id= c.cat_id
LEFT JOIN users AS u
ON u.user_id AND a.user_id
WHERE u.username = '{$user}' LIMIT 1
This statement is incomplete. I am missing a middle table here. cat_id is not actually in ratings. But items_id is from a table called items and cat_id is also in that table as well.
So what I am trying to do is this:
SELECT rating FROM ??? GROUP BY cat_id where u.user=$user
The only thing I can think of doing maybe is another LEFT join with items inside favoriteCat but I am not sure if that is allowed.
I was overthinking this, here is my final solution:
SELECT c.category, count(r.rating) AS totalCount
FROM ratings as r
LEFT JOIN items AS i
ON i.items_id = r.item_id
LEFT JOIN users AS u
ON u.user_id = r.user_id
LEFT JOIN master_cat AS c
ON c.cat_id = i.cat_id
WHERE r.user_id = '{$user_id}'
GROUP BY c.category
ORDER BY totalCount DESC

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;