I have 3 tables like so
Table 1: UserInfo
user_id userName
123 userOne
Table 2: Post
user_id postContent
123 This is test message
Table 3: LikePost
user_id likesPostId
123 This is test message
I would like to run a query to get total number of post likes, posts, and user information from those 3 tables.
I can do this for each one such as in Post table:
SELECT COUNT(*) FROM Post WHERE Post.user_id = '123'
and SELECT * FROM UserInfo WHERE UserInfo.user_id = '123'
Is anyone have better solution in just 1 query? Thank you so much!
Use a structured query (with subqueries) something like this.
SELECT u.user_id, u.userName, p.num postcount, l.num likecount
FROM UserInfo u
LEFT JOIN (
SELECT COUNT(*) num,
user_id
FROM Post
GROUP BY user_id
) p ON u.user_id = p.user_id
LEFT JOIN (
SELECT COUNT(*) num,
user_id
FROM LikePost
GROUP BY user_id
) l ON u.user_id = l.user_id
What's going on here? The two subqueries, for example
SELECT COUNT(*) num,
user_id
FROM LikePost
GROUP BY user_id
each generate a virtual table with either zero or one row per user_id, showing a count for each user_id. You then join those virtual tables to your UserInfo table.
Use LEFT JOIN because ordinary innner JOIN will suppress users that lack either posts or likes.
Try This
SELECT ui.userName,Count(p.*),
Count(lp.*) as TotalPostLikes
FROM UserInfo ui
INNER JOIN Post p on p.user_id=ui.user_id
INNER JOIN LikePost lp on lp.user_id=ui.user_id
WHERE ui.user_id = '123'
GROUP BY ui.userName
If you want to select Username, Post and Likes on post, try the following
SELECT ui.userName,p.postContent as PostContent,
(SELECT COUNT(lp.user_id) FROM LikePost lp
WHERE lp.user_id=ui.user_id) as Likes,
(SELECT COUNT(_p .user_id) FROM Post _p
WHERE _p .user_id=ui.user_id) as TotalPosts
FROM UserInfo ui
INNER JOIN Post p on p.user_id=ui.user_id
WHERE ui.user_id = '123'
Yes you can do it within one query using leftjoin on Post and LikePost like below
SELECT COUNT(*),User.userName FROM UserInfo as User
leftjoin Post as Post on Post.user_id = User.user_id
leftjoin LikePost as LikePost on LikePost.user_id = User.user_id
where Post.user_id = 123
group by Post.user_id
Related
I have 3 tables Users, posts and post_approval
Now I have page where all these posts will appear from posts table but if the post visibility is set to private then the query will check in post_approval table to see if a post status is approvad for a particular user.
So the Output for User ID 2 will be all 3 posts but User 1 & 3 can see only post id 1 and 3.
Is this the right query?
SELECT * FROM posts WHERE visiblity='public' UNION (SELECT posts.* FROM POSTS RIGHT JOIN post_approval ON post_approval.post=posts.post_id WHERE post_approval.status='approved' AND post_approval.user='2')
USER ID will be enter dynamically in the above query
Simple answer
Try this SQL statement.
SELECT * FROM Posts as p, Post_approval as pa
WHERE p.post_id = pa.post OR p.visibility = 'public' AND user_id = 2
You select from Posts and Post approval, and get only the posts which match with the the post id of the user. Furthermore you get all post with visibility public.
Long answer (union)
That's the longer solution. Using a union to combine the private post and public posts for user_id = 2.
SELECT
*
FROM
(
SELECT
u.user_id,
u.username,
p.post_id,
p.post_name,
p.visibility
FROM
Users as u,
Posts as p
WHERE
p.visibility = 'public'
union ALL
SELECT
u.user_id,
u.username,
p.post_id,
p.post_name,
p.visibility
FROM
Post_approval as a,
Users as u,
Posts as p
WHERE
a.user = u.user_id and
a.post = p.post_id and
p.visibility = 'private'
) as x
WHERE
x.user_id = 2
Another small tip:
If you have a foreign key in your tables, like Post_approval.user, name it like the primary key. So in this case Post_approval.user_id
I am going to answer your question before I offer an alternative. You have some spelling errors, an extra ( and you might need to be concerned with case-sensitivity, but otherwise it should work. Your SQL with some minor corrections:
SELECT * FROM Posts WHERE visibility='public'
UNION
SELECT Posts.* FROM Posts RIGHT JOIN Post_approval ON Post_approval.post=Posts.post_id
WHERE Post_approval.status='approved' AND Post_approval.user='2';
An alternative that does not use UNION:
select p.* from Posts p
left join Post_approval p_a on p.post_id = p_a.post and p_a.user = 2
where p.visibility = 'public' or p_a.status = 'approved';
See Db-Fiddle Demo
Another Way:
SELECT * FROM Posts
where visibility = 'Public' or post_id in (
select post from Post_approval where user = 2 and status = 'approved'
)
I have the following schema of a Mysql database:
User(Id, FirstName, LastName, NickName, Etc.)
Request(SenderId, ReceiverId)
Friendship(Id1, Id2)
I consider friendship to be an undirected relation, which means that for every friendship, I insert it twice to the Friendship table. (Let me know if this is not a good idea, please).
What I am trying to retrieve is a list of users, who are not friends to a specific user (let me name him UserX), nor have a current request ongoing to/from him.
My initial trials led me to this:
SELECT User.Id, User.NickName, User.Picture FROM User
LEFT JOIN Friendship A ON User.Id = A.Id1
LEFT JOIN Friendship B ON User.Id = B.Id2
LEFT JOIN Request C ON User.Id = C.Sender
LEFT JOIN Request D ON User.Id = D.Reciever
WHERE User.Id <> ?
And, of course the placeholder is UserX's Id.
This doesn't work because, although the tuples that has friendships or requests with UserX are eliminated, The friends still appear because they have friendships with other users!
Thanks in advance.
If you want an efficient solution, use not exists multiple times:
select u.*
from user u
where not exists (select 1 from friendship f where f.id1 = u.id and f.id2 = ?) and
not exists (select 1 from friendship f where f.id2 = u.id and f.id1 = ?) and
not exists (select 1 from request r where r.SenderId = u.id and r.ReceiverId = ?) and
not exists (select 1 from request r where r.ReceiverId = u.id and r.SenderId = ?);
In particular, this can take advantage of indexes on:
friendship(id1, id2)
friendship(id2, id1)
request(SenderId, ReceiverId)
request(ReceiverId, SenderId)
This should have much better performance than solutions that union subqueries together.
Using a left join to a union list:
select *
from User u1
left join
(
select ID2 as id
from Friendships
where ID1 = 'UserX'
union all
select ID1
from Friendships
where ID2 = 'UserX'
union all
select Sender
from Request
where Receiver = 'UserX'
union all
select Receiver
from Request
where Sender = 'UserX'
) ux
on ux.id = u1.id
where ux.id is null
and ux.id <> 'UserX'
What if you collect all distinct IDs from table "request" and "Friendship" and then select records from Users ID not available in the above list.
SELECT Id, FirstName, LastName, NickName
FROM User
WHERE ID NOT IN
(
SELECT DSTINCT Id1 ID FROM Friendship
UNION
SELECT DSTINCT Id2 FROM Friendship
UNION
SELECT DSTINCT SenderId FROM Request
UNION
SELECT DSTINCT ReceiverId FROM Request
)A
I am trying to convert below query via Joins,
SELECT DISTINCT req.*
FROM request req
WHERE (req.user_id IN (
SELECT id from user where id in (SELECT user_id FROM team_member team WHERE team.team_id IN ('344', '723')) and user.active = 1
)
OR req.user_id IN (
SELECT id from user where id in (SELECT approved_employee_id from approver where approver_id = '269') and user.active = 1
))
AND req.status = 'pending';
returns 124 records.
I have wrote below query via joins but doesn't work,
SELECT DISTINCT req.*
FROM request req
LEFT JOIN user u ON u.id = req.user_id AND u.active = 1
LEFT JOIN team_member team ON team.user_id = u.id AND team.team_id IN ('344', '723')
LEFT JOIN approver app ON app.approver_id = u.id AND app.approver_id = '269'
AND req.status = 'pending';
returns more than 500 records.
two issue with this joins, it includes those requests too where status is not pending.
Below is the schema
I have below tables
tbl_approver =
id,
approver_id (FK tbl_user),
approver_team_id (FK tbl_team),
approved_employee_id (FK tbl_user)
tbl_team_mambers =
id,
team_id (FK),
user_id (FK)
tble_user =
id,
email,
username
active
tbl_request =
id,
user_id,
status
Teams Members : A user is a member of multiple teams.
Approver :
For each team there is an approver, who is also the member of that team.
there can be direct approver of an employee regardless of team.
request : inventory requests by the user
Note : as an approver, i can be member of many teams but only approver
of some team. or some employee too.
Query wanted : as an approver i want all request of my teams whom i am approver.
For correct results of join's you need to any joined "table" return only one row for user_id. And do not use left if needed only rows existing in all tables.
SELECT req.*
FROM request req
JOIN user ON user.id=req.user_id
JOIN (
SELECT distinct approved_employee_id as user_id from approver where approver_id = '269'
UNION
SELECT distinct user_id FROM team_member team WHERE team.team_id IN ('344', '723')
) A ON req.user_id=A.user_id
where user.active = 1
AND req.status = 'pending';
Or, if needed only "real table":
SELECT DISTINCT req.*
FROM request req
JOIN user u ON u.id = req.user_id AND u.active = 1
LEFT JOIN team_member team ON team.user_id = u.id AND team.team_id IN ('344', '723')
LEFT JOIN approver app ON app.approver_id = u.id AND app.approver_id = '269'
WHERE req.status = 'pending'
AND (team.user_id is not null OR app.approver_id is not null)
Watch the LEFT JOIN syntax, here's the visual expression of joins
SELECT DISTINCT req.*
FROM request req
LEFT JOIN user u ON u.id = req.user_id AND u.active = 1
...
This will select all distinct records from request, and JOIN them to user. The join_condition after ON will only affect the join relation.
If there is no matching row for the right table in the ON or USING part in a LEFT JOIN, a row with all columns set to NULL is used for the right table.
Join syntax from Mysql Documentation
If you really want to use LEFT JOIN to filter all record from request, consider moving the condition_expr to WHERE
SELECT DISTINCT req.*
FROM request req
LEFT JOIN user u ON u.id = req.user_id
...
WHERE u.active = 1
AND ...
If you only need request that satisfies the join condition to user, you should consider use Join rather than LEFT JOIN.
There are three tables. user, like, comment. Table like and comment has rows associated to user. I need all users with their associated row count from table like and comment. It's easy to do when there is only one table associated. However, here is my query.
SELECT u.id as id, u.display_name as displayName,
COUNT(x.user_id) as likeCount,
COUNT(y.user_id) as commentCount
FROM `user` u
LEFT JOIN
`like` x ON x.user_id = u.id
LEFT JOIN
`comment` y ON y.user_id = u.id
GROUP BY u.id
Table relationships:
One user has many likes
One user has many comments
commentCount is giving correct rows count, but likeCount giving wrong rows count. Please don't post answer which uses sub queries. I want it with only ONE SELECT clause. I am using MySQL. TIA
You can get the user count per individual table, like this:
SELECT user, COUNT(*) AS t1Count
FROM table1
GROUP BY user;
SELECT user, COUNT(*) AS t2Count
FROM table2
GROUP BY user;
Then you can join those two to the Users table to get the count of each. You should use COALESCE() to return null values with 0:
SELECT u.id, COALESCE(t1.t1Count, 0), COALESCE(t2.t2Count, 0)
FROM users u
LEFT JOIN(
SELECT user, COUNT(*) AS t1Count
FROM table1
GROUP BY user) t1 ON u.id = t1.user
LEFT JOIN(
SELECT user, COUNT(*) AS t2Count
FROM table2
GROUP BY user) t2 ON u.id = t2.user;
Here is an SQL Fiddle example.
I have two tables:
users:
user_id user_name
data:
user_id user_data user_time
I wan to select the latest entry from the data table, but return the user_name, user_id, user_data and user_time.
I have tried the following query, but it returns the first entry, not the last for each user:
sql = "SELECT users.user_name, users.user_id, data.user_data, data.user_time
FROM users
INNER JOIN data ON data.user_id = users.user_id
GROUP BY users.user_name
ORDER BY data.user_time DESC";
Use GROUP BY and MAX, WHERE...IN:
SELECT u.user_id, u.user_name, d.user_data, d.user_time
FROM users u
INNER JOIN data d ON d.user_id = u.user_id
WHERE (d.user_id, d.user_time) =
(SELECT user_id, MAX(user_time) FROM data GROUP BY user_id)
I think you had better add data_id column to data table.
Unless data_id, both user_id and user_time are necessary for PRIMARY KEY(and user_time is not always unique, not reliable)
If there is data_id, it can be bitly simple:
SELECT u.user_id, u.user_name, d.user_data, d.user_time
FROM users u
INNER JOIN data d ON d.data_id =
(SELECT data_id FROM data
WHERE user_id = u.user_id ORDER BY data_time DESC LIMIT 1)