Need an alternative to two left joins - mysql

Hey guys quick question, I always use left join, but when I left join twice I always get funny results, usually duplicates. I am currently working on a query that Left Joins twice to retrieve the necessary information needed but I was wondering if it were possible to build another select statement in so then I do not need two left joins or two queries or if there were a better way. For example, if I could select the topic.creator in table.topic first AS something, then I could select that variable in users and left join table.scrusersonline. Thanks in advance for any advice.
SELECT * FROM scrusersonline
LEFT JOIN users ON users.id = scrusersonline.id
LEFT JOIN topic ON users.username = topic.creator
WHERE scrusersonline.topic_id = '$topic_id'
The whole point of this query is to check if the topic.creator is online by retrieving his name from table.topic and matching his id in table.users, then checking if he is in table.scrusersonline. It produces duplicate entries unfortunately and is thus inaccurate in my mind.

You use a LEFT JOIN when you want data back regardless. In this case, if the creator is offline, getting no rows back would be a good indication - so remove the LEFT joins and just do regular joins.
SELECT *
FROM scrusersonline AS o
JOIN users AS u ON u.id = o.id
JOIN topic AS t ON u.username = t.creator
WHERE o.topic_id = '$topic_id'

One option is to group your joins thus:
SELECT *
FROM scrusersonline
LEFT JOIN (users ON users.id = scrusersonline.id
JOIN topic ON users.username = topic.creator)
WHERE scrusersonline.topic_id = '$topic_id'

Try:
select * from topic t
left outer join (
users u
inner join scrusersonline o on u.id = o.id
) on t.creator = u.username
If o.id is null, the user is offline.

Would not it be better to match against topic_id in the topics table by moving the condition to the join. I think it will solve your problem, since duplicates come from joining with the topics table:
SELECT * FROM scrusersonline
JOIN users
ON users.id = scrusersonline.id
LEFT JOIN topic
ON scrusersonline.topic_id = '$topic_id'
AND users.username = topic.creator
By the way, LEFT JOIN with users is not required since you seem to search for the intersection between scrusersonline and users

Related

SQL Select from multiple tables return what is available

I have three tables, one for users, one for images, and one that maps the images to the users. Here is my query (simplified):
"SELECT * FROM tb_users u, tb_images i, tb_mapimagestousers m
WHERE
u.id = :userid
AND
m.userid = u.id
AND
i.id = m.imgid
This query will return fine as long as there is data to pull from all tables. If there is no image assigned to a user there will be no entry for them in the images or the mapimagestousers tables, and the query will return an empty set (understandably). How do I query the database so that, in the case of no assigned image, I still get whatever I pulled from the users table?
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Then you would know about outer joins.
You want:
SELECT *
FROM tb_users u LEFT JOIN
tb_mapimagestousers miu
ON miu.userid = u.id LEFT JOIN
tb_images i
ON miu.imgid = i.id
WHERE u.id = :userid;

Is there a better way to do this MYSQL statement?

This mysql statement gets posts that have not been flagged by the user.
As it is now, I am getting the flagged post ids, and then not getting posts in that set of ids.
SELECT * FROM posts WHERE posts.id NOT IN
(SELECT p2.id FROM posts p2 LEFT JOIN flagged_posts
ON flagged_posts.user_id = ? WHERE flagged_posts.post_id = p2.id)
I feel there is probably a better (faster) way to do this, for example with just one select and one join, but I am not sure
You can do this using clause EXISTS.
SELECT * FROM posts
WHERE
NOT EXISTS
(SELECT 1
FROM flagged_posts
WHERE flagged_posts.post_id=posts.post_id AND flagged_posts.user_id=?)
Alternatively you can do this using LEFT OUTER JOIN.
SELECT *
FROM posts
LEFT OUTER JOIN flagged_posts ON posts.post_id = flagged_posts.post_id
AND flagged_posts.user_id=?
WHERE flagged_posts.post_id IS NULL

Easy SQL Query - Aligning foreign keys

I'm taking longer than I expected with an easy Query in MySQL. I think it's gonna be a nested query but I don't see it easily.
I have 3 tables: Users, Comments, and Businesses. Comments have business_id, and user_id as foreign keys.
So I want the result of users.name and comments.review, having the number of the business.
So my First (and wrong) attempt was:
SELECT users.name, users.image, comments.review
FROM reviews JOIN users JOIN businesses
WHERE reviews.user_id=users.id AND reviews.business_id=4;
I want to set that PrimaryKey.user_id is equal to ForeignKey.users.id.
From all of the comments, I want to take these which are from the business_id=4.
It gives me failiure with both 'WHERE' clauses. So not sure if I could fix this with a nested query or maybe with a JOIN clause?
Any help will be appreciated!
Thank you all. [Edited Query]
Try this out and let me know in case of any queries.
select c.name,c.image,a.review
from
comments a
inner join
(select * from buisnesses where buisness_id = 4) b
on a.buisness_id = b.buisness_id
inner join
users c
on a.user_id = c.user_id;
or
select b.name,b.image,a.review
from
comments a
inner join
users b
on a.user_id = b.user_id
where a.buisness_id = 4;
Give this a try:
SELECT
users.name,
users.image,
comments.review
FROM reviews
JOIN users
ON reviews.user_id = users.id
JOIN businesses
ON reviews.business_id = business.business_id
WHERE reviews.business_id=4;
Since you're not using any of the columns from the business table, you could probably drop it from the query:
SELECT
users.name,
users.image,
comments.review
FROM reviews
JOIN users
ON reviews.user_id = users.id
WHERE reviews.business_id=4;

JOIN where CAN be joined, else no join

So, I have this MySQL problem.
I've been looking at LEFT JOIN, INNER JOIN etc. And as I understand LEFT JOIN joins from left and if the right part doesn't exist it's values get set to NULL. And with INNER JOIN if there is no match for the join, an empty set is returned.
As you can see from my previous statement I join different statistics and such for one of the users in the match. But if uid2 isnt friend with uid1 this will give null in my case for all fields in friends.*
How would I do to get all the friends fields if they are friends and no fields from friends if they arent. (I dont want to do a separate statement before to check if they're friends).
This is my previous statemenet:
SELECT matches.*, statistics.*, friends.*, users.username
FROM `matches`
LEFT JOIN statistics ON matches.uid1=statistics.uid
LEFT JOIN users ON matches.uid1=users.uid
LEFT JOIN friends ON matches.uid1=friends.fid AND matches.uid2=friends.uid
WHERE matches.mid IN (269,231,131)
Then you just replace the last LEFT JOIN with an INNER JOIN:
SELECT matches.*, statistics.*, friends.*, users.username
FROM `matches`
LEFT JOIN statistics ON matches.uid1=statistics.uid
LEFT JOIN users ON matches.uid1=users.uid
INNER JOIN friends ON matches.uid1=friends.fid AND matches.uid2=friends.uid
WHERE matches.mid IN (269,231,131);
However, it's not possible to selectively not return the columns from the friends table when they can't be joined.
I ended up with still doing a LEFT JOIN, and then filter the result;
$temp = array_filter($temp, "is_not_null");
function is_not_null($var)
{
return ! is_null($var);
}

How do you JOIN two MySQL tables where the data is NOT in the other table?

For example, I have a pet table and a lost pets table. I want to get all of the pets that are NOT lost with 1 join and no sub-selects. Is that possible? A typical join only returns results that are in both tables.
You're describing an OUTER JOIN as compared to a standard INNER JOIN. Google or check your documentation - I'm sure you'll find lots of examples. :)
SELECT * FROM pets AS p
LEFT OUTER JOIN lost-pets AS lp
ON p.name = lp.name
WHERE lp.id IS NULL
SELECT PETS.NAME
FROM PETS
LEFT OUTER JOIN LOST_PETS
ON PETS.PET_ID = LOST_PETS.PET_ID
WHERE LOST_PETS.PET_ID IS NULL;
It is possible, yes, say :
SELECT *
FROM pets LEFT OUTER JOIN pets-lost ON pets.id = pets-lost.id
WHERE pets-lost.id IS NULL;
Why not do where not exists (select * from Lost ...)? Its a sub-select, but I don't see why thats a problem.