Inner Join on 3 different tables - php

I have 3 different tables I need to pull data from. What needs to happen is we pull posts from the posts table where the user who made the post is set as a public user, or if set as private, users they grant access to can view their posts.
Here are the tables:
user: id, username, name, password, email, private
posts: id, title, user, date, state
privateallowed: id, privateuser, alloweduser
and here is my code where I try to get the records:
$username = $_COOKIE['username'];
$sqlposts = "select p.id, u.id, u.private, a.privateuser, a.alloweduser from user u
inner join posts p on u.id = p.user
inner join privateallowed a on a.privateuser = u.id and a.alloweduser = " . $username . "
where u.private='public' or (a.privateuser=p.user and a.alloweduser=" . $username . ")";
$resultpost = mysqli_query($dbcon, $sqlposts);
$numrows = mysqli_num_rows($resultpost);
Unfortunately, no records are being returned. Any help or ideas are appreciated.

For what it's worth (#pgngp commented about needing single quotes around '" . $username . "'):
$username = $_COOKIE['username'];
$sqlposts = "SELECT p.id, u.id, u.private, a.privateuser, a.alloweduser
FROM user u
INNER JOIN posts p ON
u.id = p.user
INNER JOIN privateallowed a ON
a.privateuser = u.id AND a.alloweduser = '" . $username . "'
WHERE u.private='public';
$resultpost = mysqli_query($dbcon, $sqlposts);
$numrows = mysqli_num_rows($resultpost)";
Also note, I've removed the following from your WHERE condition because it is redundant due to previous INNER JOIN's. We can only infer this because you've used INNER JOIN, had you used LEFT JOIN you would need to leave the condition in as-is.
. . .or (a.privateuser=p.user and a.alloweduser=" . $username . ")"
Explanation:
INNER JOIN posts p ON u.id = p.user
So we have determined that u.id = p.user
INNER JOIN privateallowed a ON a.privateuser = u.id
So we infer that a.privateuser = p.user
AND a.alloweduser = '" . $username . "'
This covers the remaining condition in your WHERE

I did find an answer, though I'm sure it isn't a perfect one. What I did was I broke the statements into separate select statements, and then embed one in the where clause, as follows:
$sqlposts = "SELECT p.id, u.id, u.private
FROM user u
INNER JOIN posts p ON u.id = p.user
WHERE u.private='public' or p.user in
(
select a.privateuser
from privateallowed a
inner join posts p on p.user = a.privateuser
where a.alloweduser=" . $username . "
)";
Me and another person who is pretty good with sql looked at this for a couple of hours, and we just couldn't get the select to return the correct results. We tried the following, but it returned each public user 3 times for some reason:
SELECT p.id, u.id, u.private
FROM user u
INNER JOIN posts p ON u.id = p.user
INNER JOIN privateallowed a on a.alloweduser=24
WHERE u.private='public' or p.user = a.privateuser
I appreciate everyone's help on this. If anyone has any other ideas, I appreciate them. I'm working on a web site that I am hoping will grow, and I want to make sure the page loads as fast as possible.

Related

Error in running any query on the phpmyadmin on the live server . But when i am runnign it on the adminer.php it is executing

I have a WordPress site on a Linux based server . The phpmyadmin is giving connectivity error . Daily it gives errors for different queries and today is giving me errors for any query which I am using .I used the same query yesterday and it helped me to fetch the data . But today it is not working . I also use the adminer.php and it is working fine and giving the data based on the query . Can anyone tell me I will give a screenshot of the error . Please give your thought on it .
Here is the query which I am running .
SELECT u.id,f.meta_value as first_name,l.meta_value as last_name,u.user_nicename as slug,u.user_email as email,u.user_pass as password,b.meta_value as badge_id,e.meta_value as expiry_date,lc.meta_value as location_id, u.emailVarification as verification_code,v.meta_value as user_verified,s.meta_value as remember_token,u.user_registered as created_at,p.post_modified as updated_at,d.meta_value as is_disabled
FROM `wp_users` as u
LEFT JOIN wp_usermeta as f ON f.user_id = u.ID AND f.meta_key = "first_name"
LEFT JOIN wp_usermeta as l ON l.user_id = u.ID AND l.meta_key = "last_name"
LEFT JOIN wp_usermeta as b ON b.user_id = u.ID AND b.meta_key = "badge_id"
LEFT JOIN wp_usermeta as e ON e.user_id = u.ID AND e.meta_key = "expiry_date"
LEFT JOIN wp_usermeta as lc ON lc.user_id = u.ID AND lc.meta_key = "location_id"
LEFT JOIN wp_usermeta as v ON v.user_id = u.ID AND v.meta_key = "_is_verified"
LEFT JOIN wp_usermeta as s ON s.user_id = u.ID AND s.meta_key = "session_tokens"
LEFT JOIN wp_usermeta as d ON d.user_id = u.ID AND d.meta_key = "is_disabled"
LEFT JOIN wp_posts as p ON p.post_author=u.id
WHERE p.post_type="freelancers"
AND u.freelancerpaid="1"
The issue was because of the Cloudfare installed on the server I tried to bypass it and everything worked . Thanks everyone for the answers .

SQL query to fetch data of a particular user, from three tables

First is a user table, second a places table and third a favorites table (having two fk, one from user and another from places). I want to get all the favorite places of one user, how do I do that?
I tried to play around with joins but what I don't know is how to get data of a particular user.
$qry =
"SELECT places.place_id , places.db_image ,places.description from places
inner join favorites on places.place_id = favorites.place_id
inner join user on user.id = favorites.user_id
";
$query=mysqli_query($con ,$qry);
$return_arr = array();
$sql = sprintf(
'SELECT
p.place_id,
p.db_image,
p.description
FROM
places p INNER JOIN
favorites f ON p.place_id = f.place_id INNER JOIN
user u ON u.id = f.user_id
WHERE
u.id = %d'
, $userId);
or if you want simply select all columns from places
SELECT
p.*
FROM
places p INNER JOIN
favorites f ON p.place_id = f.place_id INNER JOIN
user u ON u.id = f.user_id
WHERE
u.id = %d
It is better to use prepared statements, but if you are not familiar with them, this is good enough.

SQL Query JOIN syntax

I have the following tables and would like to query one more element from them.
categories table ->idcat(int), cat(varchar);
topics table ->idtopic(int), topic(varchar), idcat(int-fk), iduser(int-fk);
replies table ->idreply(int), reply(varchar) iduser(int-fk), idtopic(int-fk)
users table ->iduser(int), username(varchar).
My current query is;
$query = "SELECT t.topic, t.idtopic, u.username
FROM topics t
LEFT JOIN categories c ON t.idcat = c.idcat
LEFT JOIN users u ON t.iduser = u.iduser
WHERE c.idcat = '" . $idcat . "'";
Which presents 'Topic' and 'Username'. I'd like to show 'idReply' as well but don't know the proper JOIN syntax.
SELECT
t.topic,
t.idtopic,
u.username
FROM
topics t
LEFT JOIN
categories c ON t.idcat = c.idcat
LEFT JOIN
users u ON t.iduser = u.iduser
LEFT JOIN // new
replies r ON r.iduser = u.iduser AND r.idtopic = t.idtopic // new
WHERE c.idcat = '" . $idcat . "'";
This will generate a row for every reply to every topic in the specified category. Which could be a lot of records.
You may also want to experiment with the exact type of join on the replies table to get the result you want. LEFT JOIN is probably correct as you'll still get a result if there's no reply to a given topic. This may depend on your flavour of SQL.
OUTER JOIN & LEFT OUTER JOIN are possibilities.
Using INNER JOIN will ensure only topics with replies are returned.
You must have reply_id (foreign key) in your topics table. After that you can use this query.
$query = "SELECT t.topic, t.idtopic, u.username, r.id as reply_id
FROM topics t
LEFT JOIN categories c ON t.idcat = c.idcat
LEFT JOIN users u ON t.iduser = u.iduser
LEFT JOIN replies r ON t.reply_id = r.id
WHERE c.idcat = '" . $idcat . "'";

SQL Query with multiple joins only returning first result on final join

So I have a prepared SQL query (below) that joins 4 tables together based on the user's ID. The final relationship however is a one to many (a user can have more than one skill) so I need all rows returned where the skill ID equals the user ID. At the moment only the first row that matches the user ID in the freelancer_skill table returns. How do I get all rows to return?
SELECT
u.user_id, u.firstname, u.lastname, u.email, u.bio, u.portfolio, u.location, u.time_joined, u.image_location,
f.freelancer_id, f.jobtitle, f.priceperhour,
ut.*,
ft.testimonial, ft.testimonial_source,
fs.skill, fs.skill_rating
FROM ((((users AS u
LEFT JOIN freelancers AS f
ON u.user_id = f.freelancer_id)
LEFT JOIN user_types AS ut
ON u.user_id = ut.user_type_id)
LEFT JOIN freelancer_testimonials AS ft
ON u.user_id = ft.testimonial_id)
LEFT JOIN freelancer_skills AS fs
ON u.user_id = fs.skill_id)
WHERE
u.confirmed = :confirmed
AND u.user_id = :userID
AND ut.user_type = :userType
AND u.granted_access = :grantedAccess
EDIT
Updated code with user type WHERE clause moved into join:
SELECT
u.firstname, u.lastname, u.email, u.bio, u.portfolio, u.location, u.time_joined, u.image_location,
f.jobtitle, f.priceperhour,
ut.user_type,
ft.testimonial, ft.testimonial_source,
fs.skill, fs.skill_rating
FROM ((((" . DB_NAME . ".users AS u
LEFT JOIN " . DB_NAME . ".freelancers AS f
ON u.user_id = f.freelancer_id)
LEFT JOIN " . DB_NAME . ".user_types AS ut
ON u.user_id = ut.user_type_id AND ut.user_type = :userType)
LEFT JOIN " . DB_NAME . ".freelancer_testimonials AS ft
ON u.user_id = ft.testimonial_id)
RIGHT JOIN " . DB_NAME . ".freelancer_skills AS fs
ON u.user_id = fs.skill_id)
WHERE
u.confirmed = :confirmed
AND u.user_id = :userID
AND u.granted_access = :grantedAccess
To fetch the results I am using fetch (below). I've tried using fetchALL which does return each skill a user holds but also returns duplicates of their data for each skill.
$results->execute();
$user = $results->fetch(PDO::FETCH_ASSOC);
return $user;
Here is an SQLFiddle: http://sqlfiddle.com/#!2/d7bb3/4
You have a filter in the wrong place. You are declaring a left join to user_types but are filtering on that table in the where clause. That makes it an implicit inner join. Move
and ut.user_type = :userType
to follow this:
LEFT JOIN user_types AS ut ON u.user_id = ut.user_type_id
That might be the cause of your problem, but even if it's not, you will still get unexpected results with that filter in the where clause.
change the order of the joins. Swap the Users table and freelancer_skills table.
-This apparently does not work.
Maybe try something like this instead. Not ideal if you want to list a hundred skills for one person.
SELECT
u.firstname,
u.lastname,
u.email, u.bio, u.portfolio, u.location, u.time_joined, u.image_location,
f.jobtitle, f.priceperhour,
ut.user_type,
ft.testimonial, ft.testimonial_source,
count(case when fs.skill = 'HTML5' then 1 end) as HTML5,
count(case when fs.skill = 'CSS3' then 1 end) as CSS3,
count(case when fs.skill = 'PHP' then 1 end) as PHP,
fs.skill_rating
FROM
(
(
(
(
users AS u
LEFT JOIN freelancers AS f ON
u.user_id = f.freelancer_id
)
LEFT JOIN user_types AS ut ON
u.user_id = ut.user_type_id AND
ut.user_type = 'developer'
)
LEFT JOIN freelancer_testimonials AS ft ON
u.user_id = ft.testimonial_id
)
RIGHT JOIN freelancer_skills AS fs ON
u.user_id = fs.skill_id
)
WHERE
u.confirmed = '1'
AND u.user_id = '3'
AND u.granted_access = '1'
group by
u.firstname,
u.lastname,
u.email, u.bio, u.portfolio,
u.location,
u.time_joined, u.image_location,
f.jobtitle, f.priceperhour,
ut.user_type,
fs.skill_rating

multiple joins in mysql query

I'm making a mock twitter website, and for the main feed, i'm trying to query my database for all posts, and reposts from the users that someone follows where $user_id is the person currently logged in. But it is only showing the reposted posts when i run the query. Can anyone please give me suggestions on how to fix this problem?
$query_feed = "SELECT posts.post, posts.date, users.handle, posts.id, posts.image, users.profile_pic, repost.post_id, repost.user_id
FROM posts
JOIN users ON posts.author_id = users.id
JOIN following ON " . $user_id . " = following.follower_id
JOIN repost ON posts.id = repost.post_id
WHERE (posts.author_id = following.followee_id) OR (repost.user_id = following.followee_id)
ORDER BY posts.id desc";
If you don't want the repost table to eliminate records in the result set, you'll need to use an outer join.
Also, your join condition for the following table is in the where clause, and the where clause contains your join condition. Additionally, since your join condition for following references a field in repost, the join order is incorrect.
$query_feed = "SELECT posts.post, posts.date, users.handle, posts.id, posts.image, users.profile_pic, repost.post_id, repost.user_id
FROM posts
JOIN users ON posts.author_id = users.id
LEFT JOIN repost ON posts.id = repost.post_id
JOIN following ON (posts.author_id = following.followee_id) OR (repost.user_id = following.followee_id)
WHERE " . $user_id . " = following.follower_id
ORDER BY posts.id desc";
I'm not sure how MySQL handles things exactly, but you may still have problems with NULLs from the LEFT JOIN when you do the following table join. I'd run the query in a Query Analyzer to determine if you're getting expected results.
It is because you have an "inner join" on repost ("join" is really short for "inner join"):
JOIN repost ON posts.id = repost.post_id
Doing this means that you will only ever get a record in your result set if there is a matching record in repost
Instead try an "outer join" or "left join"
LEFT JOIN repost ON posts.id = repost.post_id
This should mean that you get records even if there is nothing in repost
I have simplified your tables a little (removed columns), but proven the point with a SqlFiddle here: http://www.sqlfiddle.com/#!2/ee33a

Categories