Get different set of data based on value on two tables - mysql

SELECT users.firstname,
users.lastname,
users.username,
users.image_url,
posts.status,
posts.created_at as created_at,
posts.updated_at as updated_at,
share.post_user_id as user_id,
posts.id,
share.message as message,
share.user_id as share_user_id
FROM `share` INNER JOIN `posts` ON share.post_id = posts.id
INNER JOIN `users` ON users.id = share.user_id
So, as you can see here, I'm getting the firstname, lastname, and username from the table users based on the users.id = share.user_id. The share table is like this:
Shares
message
user_id
post_user_id
post_id
Now how can I get the set of names based on users.id = share.post_user_id?

You just need another inner join on table users using an alias eg user2
SELECT users.firstname,
users.lastname,
users.username,
users.image_url,
posts.status,
posts.created_at as created_at,
posts.updated_at as updated_at,
share.post_user_id as user_id,
posts.id,
share.message as message,
share.user_id as share_user_id,
users2.firstname,
users2.lastname,
users2.username,
FROM `share`
INNER JOIN `posts` ON share.post_id = posts.id
INNER JOIN `users` ON users.id = share.user_id
INNER JOIN `users` AS user2 ON users2.id = post_user_id.user_id

Related

SQL Query to select posts from user and followed users is not including own posts

I'm building a query that should return the last 10 posts (default ordering) by $userId and the users it is following.
SQL Fiddle with a minimal example of the query: https://www.db-fiddle.com/f/i5ByFAXwADj5pfjCTn1g1m/2
The database structure is pretty simple:
posts (id, root, user, content)
users (id, username)
following (user_id, followed)
This is the query I'm currently using to get all posts:
SELECT posts.id, posts.content, users.id AS user_id, users.username
FROM posts
LEFT JOIN users ON posts.user = users.id
WHERE LIMIT 10
The query is working but it is listing posts from every user without distinction.
This is the query I built to exclude posts from users that $userId is not following, but it doesn't include $userId's own posts:
SELECT posts.id, posts.content, users.id AS user_id, users.username
FROM following
LEFT JOIN posts ON posts.user = '$userId' OR posts.user = following.followed
LEFT JOIN users ON posts.user = users.id
WHERE (following.user_id = '$userId' OR following.user_id = NULL) LIMIT 10
I've tried replacing the LEFT JOIN posts with an INNER JOIN and a RIGHT JOIN with no success whatsoever. I'm not able to find the error, why isn't the query including posts made by $userId?
I have also tried selecting from posts and joining followers, but it is returning duplicated content:
SELECT posts.id, posts.content, users.id AS user_id, users.username
FROM posts
LEFT JOIN following ON following.user_id = '$userId'
LEFT JOIN users ON posts.user = users.id
WHERE (posts.user = '$userId' OR posts.user = following.followed)
LIMIT 10;
I was about to post a UNION solution
SELECT
post_id,
content,
user_id,
username
FROM
(SELECT
posts.id post_id,
content,
users.id user_id,
username
FROM
posts INNER JOIN
users
ON user = users.id
UNION SELECT
posts.id,
content,
users.id,
username
FROM
posts INNER JOIN (
following INNER JOIN
users
ON user_id = users.id
) ON user = followed
) p
WHERE
user_id = 1
LIMIT 10;
Then I saw #Gordon Linoff's solution which might be better - more concise, at least - but I don't think it works as posted.
SELECT
posts.id,
content,
users.id,
username
FROM
posts INNER JOIN
users
ON user = users.id
WHERE
users.id = 1
OR EXISTS (
SELECT
*
FROM
following
WHERE
followed = user
AND user_id = 1
)
LIMIT 10;
Get the posts from the table posts under your conditions and join to users:
select p.id, p.content, u.id AS user_id, u.username
from (
select *
from posts
where user = '$user_id'
or user in (select user_id from following where followed = '$user_id')
) p inner join users u on u.id = p.user
order by p.id desc limit 10
Note that as it is your requirement the results may not contain posts by the user '$user_id' if the last 10 posts are from the users that this user follows.
See the demo.
I'm building a query that should return the last 10 posts by $userId and the users it is following.
So, there are two tasks here:
Get first N records per group
Apply query to given user PLUS the same for the related users
I would do something like this (pseudo code):
ids = query('SELECT user_id FROM following WHERE followed = :id)', userId).pluck('user_id');
ids.push(userId);
SELECT x.id, x.user_id, x.content
FROM (
SELECT #num := IF(#id = user_id, #num + 1, 1) AS num,
#id := posts.user_id as x_user_id,
posts.*
FROM
(SELECT #num := null, #id := null) x,
posts
WHERE posts.user_id IN(:ids)
ORDER BY posts.id DESC
) AS x
WHERE x.num <= 10
(https://www.db-fiddle.com/f/aiBUwqDApJp6foyq13ZZ2u/1)
See:
S.O.: get first N records per group
S.O.: prepared statement with WHERE IN
If I understand correctly, you basically want an EXISTS clause:
SELECT p.id, p.content, u.id AS user_id, u.username
FROM posts p JOIN
users u
ON p.user = u.id
WHERE u.id <> ? -- ? is the userid AND
EXISTS (SELECT 1
FROM following f
WHERE f.followed = ? AND
f.user_id = u.id
)
LIMIT 10;

Joining 3 tables in PHP query

Alright so for some reason I cant join 3 tables properly in with PHP and MySQL. My query worked with 2 but with 3 it wont.
select users.username,
users.ID,
users.currentTime,
users.gender,
user_ranks.likes as likes,
user_ranks.disslikes as diss,
profiles.img_url as URL
from users
inner join profiles,
user_ranks on users.ID = profiles.userID LIMIT 1
You need to join both tables with an ON clause:
select users.username,
users.ID,
users.currentTime,
users.gender,
user_ranks.likes as likes,
user_ranks.disslikes as diss,
profiles.img_url as URL
from users
inner join profiles on users.ID = profiles.userID
inner join user_ranks on user_ranks.ID = profiles.userID
LIMIT 1
SELECT
users.username,
users.ID,
users.currentTime,
users.gender,
user_ranks.likes as likes,
user_ranks.disslikes as diss,
profiles.img_url as URL
FROM users
INNER JOIN profiles ON users.ID = profiles.userID
INNER JOIN tbl_3 ON users.col = tbl_3.fk
LIMIT 1
You need to do a join for each of the tables. for Example:
select users.username,
users.ID,
users.currentTime,
users.gender,
user_ranks.likes as likes,
user_ranks.disslikes as diss,
profiles.img_url as URL from users
inner join profiles on users.ID = profiles.userID
inner join user_ranks on users.ID= user_ranks.ID LIMIT 1
SELECT users.username,
users.ID,
users.currentTime,
users.gender,
user_ranks.likes as likes,
user_ranks.disslikes as diss,
profiles.img_url as URL
FROM users
INNER JOIN profiles
on users.ID = profiles.userID
INNER JOIN user_ranks
on user_ranks.ID = profiles.userID
LIMIT 1

mysql - get all post with comment count and user from users, posts and comments table

I have 3 tables of users, posts and comments. Users table fields are
Id, name, gender, phone
posts table fields are
post_id, user_id, posts, time
comments table fields are
id, user_id, comment, post_id, time
i wants to get value of these fields
name, gender, posts, time, count(comments)
SELECT
x.*, CONCAT(u.FirstName, ' ', u.LastName) AS name, u.Gender AS gender
FROM (
SELECT
p.id , p.post, p.date_time, p.user_id AS uid, COUNT(c.post_id) AS 'count'
FROM
posts p
LEFT JOIN
comments c ON p.id = c.post_id
GROUP BY
p.id
) x
LEFT JOIN
users u ON u.id = uid
Try as this:
Here 0 will replace if comments.id is null
SELECT User.name, User.gender, posts.posts, count(distinct ifnull(comments.id, 0)) as commentcount
FROM User
JOIN posts on user.id = posts.user_id
JOIN comments on user.id =comments.user_id
GROUP User.name, posts.posts
If you want to group with gender add User.gender to group by.

Mysql inner join -> if null return null else return name

I have the following query:
SELECT
projects.id AS project_id,
projects.name AS project_name,
projects_tasks.id AS task_id,
projects_tasks.name AS task_name,
projects_tasks_timings.id AS timing_id,
projects_tasks_timings.registered_time AS timing_time,
projects_tasks_timings.edit_reason AS timing_description,
projects_tasks_timings.date AS timing_date,
projects_tasks_timings.created_at AS timing_date2,
projects_tasks_timings.updated_at AS timing_date3,
users.name AS timing_user_name,
users.surname AS timing_user_surname,
users2.name AS timing_user_name_update,
users2.surname AS timing_user_surname_update
FROM `projects_tasks_timings`
INNER JOIN `users`
ON users.id = projects_tasks_timings.user_id
INNER JOIN `users`
AS users2 ON users2.id = projects_tasks_timings.updated_by
INNER JOIN `projects_tasks`
ON projects_tasks.id = projects_tasks_timings.task_id
INNER JOIN `projects`
ON projects.id = projects_tasks.project_id
$task_clause
$user_clause
LIMIT $limit OFFSET $start
This should return a lot of data, but it doesn't. I think because the inner join on users2 doesn't match any columns as they are all null values.
What I want to achieve is:
If it has no matches it should return null. If there are matches, it should return the users' names.
I've look through some question using a where clause on the inner join, but had no success so far.
Can anyone help me with this? Thanks!
Just use LEFT JOIN instead if INNER JOIN
SELECT
projects.id AS project_id,
projects.name AS project_name,
projects_tasks.id AS task_id,
projects_tasks.name AS task_name,
projects_tasks_timings.id AS timing_id,
projects_tasks_timings.registered_time AS timing_time,
projects_tasks_timings.edit_reason AS timing_description,
projects_tasks_timings.date AS timing_date,
projects_tasks_timings.created_at AS timing_date2,
projects_tasks_timings.updated_at AS timing_date3,
users.name AS timing_user_name,
users.surname AS timing_user_surname,
users2.name AS timing_user_name_update,
users2.surname AS timing_user_surname_update
FROM `projects_tasks_timings`
INNER JOIN `users`
ON users.id = projects_tasks_timings.user_id
INNER JOIN `projects_tasks`
ON projects_tasks.id = projects_tasks_timings.task_id
INNER JOIN `projects`
ON projects.id = projects_tasks.project_id
LEFT JOIN `users`
AS users2 ON users2.id = projects_tasks_timings.updated_by
$task_clause
$user_clause
LIMIT $limit OFFSET $start

How to order a query by column if some of its values are null?

I have two tables posts and posts_replies I queried all posts and order them by timestamp (post time).
Now I want to do the following :
Any time a user make a reply for any post I want to put that post at the top of the wall
so I did get the max replies' timestamp of each post and order the posts using the max timestamp of the replies of specific post.
The problem is that some posts does not have any replies so the max timestamp_of_replies of this post will be NULL so I want to know : Does it possible to order the result by timestamp_of_replies when it is not null and by post_timestamp when it is NULL.
My query :
SELECT
posts.*,
u1.id as user_id,
u1.avatar,
u1.username as poster_username,
u2.username as posted_username ,
posts.timestamp,
f1.recent_reply_time
FROM
posts
INNER JOIN
users u1
ON posts.poster_id = u1.id
INNER JOIN
users u2
ON posts.posted_id = u2.id
LEFT JOIN (
SELECT
max(timestamp) as recent_reply_time,
post_id
FROM
posts_replies
GROUP BY post_id) f1
ON f1.post_id = posts.id
order by
f1.recent_reply_time DESC
Note : order by f1.recent_reply_time, posts.timestamp DESC did not give me right results
MySQL has an IF() function, that you may also use in the ORDER BY clause:
ORDER BY IF(column IS NULL, othercolumn, column)
in your case it would be:
ORDER BY IF(f1.recent_reply_time IS NULL, posts.timestamp, f1.recent_reply_time)
Use COALESCE:
SELECT posts.*, u1.id as user_id, u1.avatar, u1.username as poster_username,
u2.username as posted_username , posts.timestamp, f1.recent_reply_time
FROM posts
INNER JOIN users u1 ON posts.poster_id = u1.id
INNER JOIN users u2 ON posts.posted_id = u2.id
LEFT JOIN (SELECT max(timestamp) as recent_reply_time, post_id
FROM posts_replies
GROUP BY post_id) f1 ON f1.post_id = posts.id
ORDER BY COALESCE(f1.recent_reply_time,[alternative value (CURDATE())]) DESC
SORTING is easily readable and maintainable, if you make it based on what you select. Better have some sortkey in your select and use it in ORDER BY.
i have used COALESCE to handle nulls. Makes ure sortkey atleast have one NOT NULL value, by using suitable arguments to COALESCE
SELECT posts.*,
u1.id as user_id,
u1.avatar,
u1.username as poster_username,
u2.username as posted_username,
posts.timestamp,
f1.recent_reply_time,
COALESCE(f1.recent_reply_time,posts.timestamp) as sortkey
FROM posts
INNER JOIN users u1 ON posts.poster_id = u1.id
INNER JOIN users u2 ON posts.posted_id = u2.id
LEFT JOIN (SELECT max(timestamp) as recent_reply_time, post_id FROM posts_replies GROUP BY post_id) f1 ON f1.post_id = posts.id
order by sortkey DESC