MySQL Selecting from multiple rows - mysql

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

use 2 left join can't work but separately can get results

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;

SQL - inner join on different criteria

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;

mySQL Sub Select needed

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.

MySQL SELECT Query where clause in a selection

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

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