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.
Related
I have three tables, company, user and share. I want to count one company's user and share, they are not relevant.
There may be a row that has share value but not user value. so I used left join, I can get results separately, but it doesn't work together.
Here is my query:
SELECT c.name, count(u.company_id), count(s.company_id)
FROM company c
LEFT JOIN user u
ON c.id=u.company_id and u.company_id=337
WHERE u.company_id is NOT NULL
LEFT JOIN share s
ON c.id=s.id AND s.company_id=337
WHERE s.company_id is NOT NULL
You need to do at least one of the counts in a subquery. Otherwise, both counts will be the same, since you're just counting the rows in the resulting cross product.
SELECT c.name, user_count, share_count
FROM company AS c
JOIN (SELECT company_id, COUNT(*) AS user_count
FROM users
GROUP BY company_id) AS u
ON u.company_id = c.id
JOIN (SELECT company_id, COUNT(*) AS share_count
FROM share
GROUP BY company_id) AS s
ON s.company_id = c.id
WHERE c.company_id = 337
Another option is to count the distinct primary keys of the tables you're joining with:
SELECT c.name, COUNT(DISTINCT u.id) AS user_count, COUNT(DISTINCT s.id) AS share_count
FROM company AS c
JOIN users AS u on u.company_id = c.id
JOIN share AS s ON s.company_id = c.id
WHERE c.company_id = 337
Your code looks okay, except for the extra WHERE clause. However, you probably want COUNT(DISTINCT), because the two counts will return the same value:
SELECT c.name, count(distinct u.company_id), count(distinct s.company_id)
FROM company c LEFT JOIN
user u
ON c.id = u.company_id and u.company_id=337 LEFT JOIN
share s
ON c.id = s.id AND s.company_id=337
WHERE s.company_id is NOT NULL AND u.company_id IS NOT NULL;
Just getting confused on basic stuff -
could someone explain me this -
select s.name from students s
inner join friends f on f.id = s.id
inner join packages p on p.id = s.id
where p.salary < (select pp.salary from packages pp where pp.id = f.friend_id)
order by (select pp.salary from packages pp where pp.id = f.friend_id) ASC;
the salary comparison part - i.e select pp.salary from packages pp where pp.id = f.friend_id should not yield the same salary result? - so how can we compare.
for references, use the below sample tables
table 1- students
columns - id, name
table 2 - friends (here each id is linked with one friend_id (his best friend))
columns - id , friend_id
table3 - packages
columns - id , salary
Trying to find out the name of the friend whose best friend's salary is more than his salary.
I am confused at understanding this solution.
That where subquery part is wrong cause the subquery will return multiple record and which can't be used with < operator since it's accepts scalar value. Rather change that to a JOIN as well like
JOIN packages pp ON pp.id = f.friend_id
AND p.salary < pp.salary
Change your query to be
select s.name from students s
inner join friends f on f.id = s.id
inner join packages p on p.id = s.id
JOIN packages pp ON pp.id = f.friend_id
AND p.salary < pp.salary
order by pp.salary;
I have three tables, libraryitems, copies and loans.
A libraryitem hasMany copies, and a copy hasMany loans.
I'm trying to get the latest loan entry for a copy only; The query below returns all loans for a given copy.
SELECT
libraryitems.title,
copies.id,
copies.qruuid,
loans.id AS loanid,
loans.status,
loans.byname,
loans.byemail,
loans.createdAt
FROM copies
INNER JOIN libraryitems ON copies.libraryitemid = libraryitems.id AND libraryitems.deletedAt IS NULL
LEFT OUTER JOIN loans ON copies.id = loans.copyid
WHERE copies.libraryitemid = 1
ORDER BY copies.id ASC, loans.createdAt DESC
I know there needs to be a sub select of some description in here, but struggling to get the correct syntax. How do I only return the latest, i.e MAX(loans.createdAt) row for each distinct copy? Just using group by copies.id returns the earliest, rather than latest entry.
Image example below:
in the subquery , getting maximum created time for a loan i.e. latest entry and joining back with loans to get other details.
SELECT
T.title,
T.id,
T.qruuid,
loans.id AS loanid,
loans.status,
loans.byname,
loans.byemail,
loans.createdAt
FROM
(
SELECT C.id, C.qruuid, L.title, MAX(LN.createdAt) as maxCreatedTime
FROM Copies C
INNER JOIN libraryitems L ON C.libraryitemid = L.id
AND L.deletedAt IS NULL
LEFT OUTER JOIN loans LN ON C.id = LN.copyid
GROUP BY C.id, C.qruuid, L.title) T
JOIN loans ON T.id = loans.copyid
AND T.maxCreatedTime = loans.createdAt
A self left join on loans table will give you latest loan of a copy, you may join the query to the other tables to fetch the desired output.
select * from loans A
left outer join loans B
on A.copyid = B.copyid and A.createdAt < B.createdAt
where B.createdAt is null;
This is your query with one simple modification -- table aliases to make it clearer.
SELECT li.title, c.id, c.qruuid,
l.id AS loanid, l.status, l.byname, l.byemail, l.createdAt
FROM copies c INNER JOIN
libraryitems li
ON c.libraryitemid = li.id AND
li.deletedAt IS NULL LEFT JOIN
loans l
ON c.id = l.copyid
WHERE c.libraryitemid = 1
ORDER BY c.id ASC, l.createdAt DESC ;
With this as a beginning let's think about what you need. You want the load with the latest createdAt date for each c.id. You can get this information with a subquery:
select l.copyid, max(createdAt)
from loans
group by l.copyId
Now, you just need to join this information back in:
SELECT li.title, c.id, c.qruuid,
l.id AS loanid, l.status, l.byname, l.byemail, l.createdAt
FROM copies c INNER JOIN
libraryitems li
ON c.libraryitemid = li.id AND
li.deletedAt IS NULL LEFT JOIN
loans l
ON c.id = l.copyid LEFT JOIN
(SELECT l.copyid, max(l.createdAt) as maxca
FROM loans
GROUP BY l.copyid
) lmax
ON l.copyId = lmax.copyId and l.createdAt = lmax.maxca
WHERE c.libraryitemid = 1
ORDER BY c.id ASC, l.createdAt DESC ;
This should give you the most recent record. And, the use of left join should keep all copies, even those that have never been leant.
SELECT *, j.company_id as companyid, j.id as jid, p.id as pid, f.id as fave_id, f.user_id as user_id
FROM people p
LEFT JOIN job j
ON p.job_id = j.id
LEFT JOIN favourites f
ON p.id = f.people_id
WHERE p.company_id = 1
ORDER BY p.id ASC
I have the above MySQL Query which works fine, the last two pieces of the selection are what I need to sort out though.
In each row by default they output null otherwise they output integers such as fave_id as 46 and user_id as 6
What I actually need to figure out is if it is possible to output from the SELECT part of the query if both fave_id and user_id are not null in my head its something like this
SELECT *, j.company_id as companyid, j.id as jid, p.id as pid, f.id as fave_id, f.user_id as user_id, [if fave_id && user_id then favorite = true]
FROM people p
LEFT JOIN job j
ON p.job_id = j.id
LEFT JOIN favourites f
ON p.id = f.people_id
WHERE p.company_id = 1
ORDER BY p.id ASC
A CASE statement would work to check values and return a desired value:
SELECT *, j.company_id as companyid, j.id as jid, p.id as pid, f.id as fave_id, f.user_id as user_id,
(CASE WHEN fave_id IS NOT NULL AND user_id IS NOT NULL THEN 1 ELSE 0 END) AS favorite
FROM people p
LEFT JOIN job j
ON p.job_id = j.id
LEFT JOIN favourites f
ON p.id = f.people_id
WHERE p.company_id = 1
ORDER BY p.id ASC
Use and:
fave_id is not null and user_id is not null
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