I have the following query:
SELECT u.id, u.name, u.date_registered, p.time_created
FROM users u JOIN
prospect_notes p
ON u.id=p.subject_id
WHERE u.allocated_instructors = 668
AND p.time_created = (SELECT MAX(p2.time_created) FROM prospect_notes p2 WHERE p2.subject_id = p.subject_id)
ORDER BY p.time_created;
My problem is that when there are no rows in the prospect_notes table which match the following:
AND p.time_created = (SELECT MAX(p2.time_created) FROM prospect_notes p2 WHERE p2.subject_id = p.subject_id)
I get no result.
Instead, I want all the rows in the users table to return (presumably p.time_created would be NULL in such cases).
You need to be careful because of the JOIN clause. Presumably, if there are no matches for the correlated subquery, there are no matches in the JOIN either.
So, use LEFT JOIN and move the logic to the FROM clause:
SELECT u.id, u.name, u.date_registered, p.time_created
FROM users u LEFT JOIN
prospect_notes p
ON u.id = p.subject_id LEFT JOIN
(SELECT p2.subject_id, MAX(p2.time_created) as max_time_created
FROM prospect_notes p2
GROUP BY p2.subject_id
) p2
ON p2.subject_id = p.subject_id AND p2.time_created = p.time_created
WHERE u.allocated_instructors = 668
ORDER BY p.time_created;
That said, if you only want time_created from prospect_notes, then use a simpler query:
SELECT u.id, u.name, u.date_registered, MAX(p.time_created)
FROM users u LEFT JOIN
prospect_notes p
ON u.id = p.subject_id
WHERE u.allocated_instructors = 668
GROUP BY u.id -- okay, assuming id is unique or a primary key
ORDER BY MAX(p.time_created);
You need LEFT JOIN this clause permit you to have NULL values in the right table.
Try :
SELECT u.id, u.name, u.date_registered, p.time_created
FROM users u
LEFT JOIN prospect_notes p
ON u.id=p.subject_id
WHERE u.allocated_instructors = 668
AND p.time_created = (SELECT MAX(p2.time_created) FROM prospect_notes p2 WHERE p2.subject_id = p.subject_id)
ORDER BY p.time_created;
Related
I have a query with one LEFT JOIN that works fine. When I add a second LEFT JOIN to a table with multiple records per field in the first table, however, I am getting the product of the results in the two tables ie books x publishers returned. How can I prevent this from happening?
SELECT a.*,b.*,p.*, group_concat(b.id as `bids`)
FROM authors `a`
LEFT JOIN books `b`
ON b.authorid = a.id
LEFT JOIN publishers `p`
on p.authorid = a.id
GROUP by a.id
EDIT:
Figured it out. The way to do this is to use subqueries as in this answer:
SELECT u.id
, u.account_balance
, g.grocery_visits
, f.fishmarket_visits
FROM users u
LEFT JOIN (
SELECT user_id, count(*) AS grocery_visits
FROM grocery
GROUP BY user_id
) g ON g.user_id = u.id
LEFT JOIN (
SELECT user_id, count(*) AS fishmarket_visits
FROM fishmarket
GROUP BY user_id
) f ON f.user_id = u.id
ORDER BY u.id;
If you do multiple LEFT Joins, your query will return a cartesian product of the results. To avoid this and get only one copy of fields you desire, do a subquery for each table you wish to join as below. Hope this helps someone in the future.
SELECT u.id
, u.account_balance
, g.grocery_visits
, f.fishmarket_visits
FROM users u
LEFT JOIN (
SELECT user_id, count(*) AS grocery_visits
FROM grocery
GROUP BY user_id
) g ON g.user_id = u.id
LEFT JOIN (
SELECT user_id, count(*) AS fishmarket_visits
FROM fishmarket
GROUP BY user_id
) f ON f.user_id = u.id
ORDER BY u.id;
I have two tables, one with settingIDs and values of those settings for each userID and another with userIDs, their emails and user names.
I am trying to join the values of specific settings, the problem is that not all users have this specific setting tied to their ID, so I end up with less rows than I actually need.
Table 1
userID settingID settingValue
Table 2
userID userDOB userEmail userName
My query looks like this:
SELECT u.userID, u.userEmail, s.settingValue
FROM users u
LEFT JOIN userSettings s ON u.userID = s.userID
WHERE s.settingID = 1
What do I need to do to get all of the users in the list?
Your where clause turns you left join into an inner join. Put the condition in the JOIN
SELECT u.userID, u.userEmail, s.settingValue
FROM users u
LEFT JOIN userSettings s ON u.userID = s.userID
AND s.settingID = 1
you can use UNION ALL clause to combine two JOINS
SELECT u.userID, u.userEmail, s.settingValue
FROM users u
LEFT userSettings s
ON u.userID = s.userID
UNION ALL
SELECT u.userID, u.userEmail, s.settingValue
FROM users u
RIGHT userSettings s
ON u.userID = s.userID
i have query
SELECT P.*, COUNT(L.to) AS likes, U.name AS ownerName, U.username AS ownerUsername,
U.picture AS ownerPicture
FROM sn_posts P LEFT JOIN sn_users AS U
ON U.id = P.ownerID
LEFT JOIN sn_likes AS L
ON L.to = P.id
WHERE (P.ownerID = 69)
GROUP BY P.id
ORDER BY P.id DESC
it's taking - 0.3337 sec time,
Add an index for table sn_posts with ownerID field may
be nicer
I have the following SQL query:
SELECT users.user_id,
users.first_name,
users.last_name,
roles.role,
roles.role_id,
users.username,
users.description,
users_vs_teams.team_id,
teams.team_name,
teams.status,
teams.notes
FROM teams
INNER JOIN users_vs_teams ON teams.team_id = users_vs_teams.team_id
RIGHT OUTER JOIN users ON users_vs_teams.user_id = users.user_id
INNER JOIN roles ON users.role_id = roles.role_id
WHERE( users.role_id = 3 ) AND ( teams.status = 'Completed' ) OR ( teams.status IS NULL )
I want to display only users with a role_id of 3 but team.status can be either Completed or NULL. However, this query displays all roles where teams.status is either Completed or NULL. Any help resolving this issue will be greatly appreciated.
First, I'm not sure if you need an outer join for this. Second, your problem seems to be parentheses in the WHERE clause:
SELECT u.user_id, u.first_name, u.last_name, r.role, r.role_id,
u.username, u.description, uvt.team_id,
t.team_name, t.status, t.notes
FROM teams t INNER JOIN
users_vs_teams uvt
ON t.team_id = uvt.team_id INNER JOIN
users u
ON uvt.user_id = u.user_id
roles r
ON u.role_id = r.role_id ON u
WHERE (u.role_id = 3) AND (t.status = 'Completed' OR t.status IS NULL)
Note that table aliases make the query easier to write and to read.
Remove the RIGHT OUTER JOIN and fix your parenthesis in your WHERE clause.
SELECT users.user_id,
users.first_name,
users.last_name,
roles.role,
roles.role_id,
users.username,
users.description,
users_vs_teams.team_id,
teams.team_name,
teams.status,
teams.notes
FROM teams
INNER JOIN users_vs_teams ON teams.team_id = users_vs_teams.team_id
INNER JOIN users ON users_vs_teams.user_id = users.user_id
INNER JOIN roles ON users.role_id = roles.role_id
WHERE( users.role_id = 3 ) AND ( teams.status = 'Completed' OR teams.status IS NULL)
you can also do something like this:
( teams.status = 'Completed' OR ISNULL(teams.status,'') = '')
My query is
select COUNT(*) from result
where test_id in (select test_id
from test_schedule
where scheduler_id in (select user_id
from users
where user_type=1))
Try this:
SELECT COUNT(r.*)
FROM result r
INNER JOIN test_schedule s ON r.test_id = s.test_id
INNER JOIN users u ON s.scheduler_id = u.user_id
WHERE u.user_type = 1
SELECT COUNT(*)
FROM result r
JOIN (SELECT DISTINCT test_id
FROM test_schedule s
JOIN users u ON s.scheduler_id = u.user_id
WHERE u.user_type = 1) s
USING (test_id)
The DISTINCT is necessary to keep rows from being multiplied by all the rows in the other tables that match.
SELECT COUNT(r.*)
FROM result r
RIGHT JOIN test_schedule s USING(test_id)
RIGHT JOIN users u ON s.scheduler_id = u.user_id
WHERE u.user_type = 1