I would like to order the results by the count(*) of two related tables entries.
So I would like to get the top ordered user IDs that have more comments + posts interactions.
User Table:
ID Name ...
1 Jonh
2 Mark
3 King
4 Doe
Post Table:
ID USER_ID...
1 1
2 1
3 3
4 1
Comment Table:
ID USER_ID...
1 1
2 3
3 1
4 4
Ordered by POSTs count(*):
SELECT user.*, COUNT(post.user_id) AS count FROM user
LEFT JOIN post ON user.id = post.user_id
GROUP BY user.id
ORDER BY count DESC
Ordered by COMMENTs count(*)
SELECT user.*, COUNT(comment.user_id) AS count FROM user
LEFT JOIN comment ON user.id = comment.user_id
GROUP BY user.id
ORDER BY count DESC
Ordered by POSTs + COMMENTs count(*)
Expected Result:
user_id: 1 (four interactions), 3 (two interactions), 4 (one interaction)
SELECT u.*, COUNT(interact.user_id)
FROM user u
LEFT JOIN ( SELECT user_id FROM post
UNION ALL
SELECT user_id FROM comment
) interact
ON u.user_id = interact.user_id
GROUP BY u.user_id
If you want more detail can use conditional count
SELECT u.*,
COUNT(CASE WHEN source = 'p' then 1 END) as total_p,
COUNT(CASE WHEN source = 'c' then 1 END) as total_c,
COUNT(interact.user_id) as total_interact
FROM user u
LEFT JOIN ( SELECT user_id, 'p' as source FROM post
UNION ALL
SELECT user_id, 'c' as source FROM comment
) interact
ON u.user_id = interact.user_id
GROUP BY u.user_id
Related
I have 4 tables,
I'm trying to get all the chats that belong to the user with the id of 1, I can do that shown in the query below however I'm unsure of how efficient it is.
Secondly, I want to make this query a bit more complex by also getting all the other users which are in the chats along with the user that has the id of 1 however I'm unsure how to do this.
select * from chat_users left join chats on chat_users.chat_id = chats.id left join users on chat_users.user_id = users.id where user_id = 1
Users - id, username
Chats - id, chatname
chat_users id, user_id, chat_id
Posts - post, id, text
E.g.
If we imagine chats table as:
id : 1 | chatname : FirstChat
Chat_users as
id : 1 | user_id : 1 | chat_id : 1
id : 2 | user_id : 2 | chat_id : 1
Users as
id: 1 | username: firstUser
id: 2 | username: secondUser
I eventually want to end up with a query that returns all the chats that user1 is involved in along with the data for the other users in them chats however I'm not sure how I would do that?
Here is one way to phrase the query:
select c.*, u.*
from chat_users cu
inner join chats c on c.id = cu.chat_id
inner join users u on u.id = cu.user_id
where exists (
select 1 from chat_users cu1 where cu1.chat_id = cu.chat_id and cu1.user_id = 1
)
Perhaps you just want an aggregation:
select chat_id,
group_concat( case when cu.user_id <> 1 then user_id end) as other_users
from chat_users cu
group by chat_id
having sum( cu.user_id = 1 ) > 0;
This returns the chat id and the users -- which is what you are asking for. You can join in other information if you want.
here's my data structure:
users
id user
-----------------------
1 foo
2 bar
rooms_available
id id_user name
----------------------
1 2 room #1
2 2 room #2
3 2 room #3
4 2 room #3
i would like getting the following result:
id_user user rooms
-----------------------------
2 bar 1,2,3,4
any ideas?
thanks
You should use GROUP_CONCAT. For example:
SELECT users.id as id_user,
users.name as user,
GROUP_CONCAT(DISTINCT rooms_available.id) as rooms
FROM users
JOIN rooms_available ON users.id = rooms_available.id_user
select u.id as id_user, a.user, b.rooms
from
users u
inner join (select id_user, group_concat(`name`) as rooms from rooms_available group by 1) b on u.id=b.id_user
Try this:
SELECT a.id, a.user, GROUP_CONCAT(DISTINCT b.id ORDER BY b.id)
FROM users a
JOIN rooms_available b
ON a.id = b.id_user
I have two tables: users and works
I need write select query for count different names from users table where work_status = 1 from works table
The total is: 3 John, 1 Tom
I need get result:
John 2 (2 because one John work_status = 0 ant this not counting)
Tom 1
I have write select that can count different names, just need compared work_status..
SELECT name,COUNT(*) as num FROM users GROUP BY name
My query return:
There is a problem in your question. So here you have two solutions.
If there are three different John working on the company, this is your query
SELECT u.name, COUNT(*) as num
FROM users u INNER JOIN works w ON w.user_id = u.id
WHERE w.work_status = 1
GROUP BY u.name, u.id
If there are only one John working in the company, your query is this one:
SELECT u.name, COUNT(*) as num
FROM users u INNER JOIN works w ON w.user_id = u.id
WHERE w.work_status = 1
GROUP BY u.name
Note: If three John are the same person, you should delete the 2 last and on the works table change user_id = 3 and user_id = 4 for user_id = 1
This is a simple JOIN query:
SELECT u.name, COUNT(*) num
FROM users u
JOIN works w
ON w.user_id = u.id
AND w.work_status = 1
GROUP BY u.name
This one should do the job:
SELECT users.name,SUM(works.work_status) as num
FROM users,works
WHERE users.id=works.id
GROUP BY name
SELECT
users.`name`,
COUNT(*) num
FROM
users,
works
WHERE users.`id` = works.`user_id`
AND works.`work_status` = 1
GROUP BY users.`name` ;
I have a table of users which hold a a users id that they voted for like this:
uid | voted_for
1 | 3
2 | 3
3 | 1
What i'm aiming to do is order uid based on how many people have voted for that uid. But I have no idea how to do it.
So the end result would be:
uid | Total_Votes
3 | 2
1 | 1
2 | 0
Hope you can help explain the best way to structure the SQL for this.
Perhaps something like this will help joining the table on itself:
SELECT u.*, voted_for_cnt
FROM users u
LEFT JOIN (
SELECT voted_for, count(1) voted_for_cnt
FROM users
GROUP BY voted_for
) t ON u.uid = t.voted_for
ORDER BY t.voted_for_cnt DESC
SQL Fiddle Demo
This simple query will produce the output you requested:
select voted_for as uid, count(*) as total_votes
from users
group by 1
order by 2 desc
If you want all data about each user in the output, join users to itself:
select u.*, count(v.uid) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2,3,4,5 -- put as many numbers here as there are columns in the users table
order by total_votes desc
This second query will give a total_votes score of zero if no one voted for the user.
Alternatively, you can select only those columns you want:
select u.uid, u.name, count(v.uid) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2
order by 3 desc
```
To return only the winners, do this:
select u.uid, u.name, count(*) as total_votes
from users u
left join users v on v.voted_for = u.uid
group by 1,2
having count(*) = (
select max(c) from (
select count(*) as c from users group by voted_for))
order by 3 desc
I have 4 tables:
Users
record_id first_name last_name
1 John Smith
2 Jim Brown
3 Jane Goodall
Polls
record_id poll_question
1 What is your age?
2 What is your occupation?
Poll Options
record_id poll_id option_text
1 1 16-20
2 1 21-25
3 2 builder
4 2 technician
Poll Votes
record_id user_id poll_id option_id
1 1 1 1
2 1 2 1
3 2 1 2
4 2 2 1
Given a specified user, how do I get all OTHER users who selected the same options for the polls answered by the specified user.
Ideally, it would provide a descending list of users according to how many questions were answered the same, i.e. users who voted all exactly the same would be at the top, down to users with no answers in common.
SELECT u.first_name, u.last_name, v.Answers
FROM Users AS u
LEFT JOIN (
SELECT pv.user_id AS user, COUNT(*) AS Answers
FROM PollVotes AS pv
WHERE ((poll_id, option_id) IN
(
SELECT poll_id, option_id
FROM PollVotes
WHERE user_id = YOURUSER
))
AND pv.user_id != YOURUSER
GROUP BY pv.user_id
) AS v
ON u.record_id = v.user
WHERE u.record_id != YOURUSER
ORDER BY v.Answers DESC
The inner query selects all users with the same (poll_id, option_id) combination as the selected user. The rowcount per user is the number of common answers. The left join with the user table is to include users with no common answers in the result.
Here's another approach:
SELECT u1.record_id, u1.first_name, u1.last_name, u2.record_id comp_record_id, u2.first_name comp_first_name, u2.last_name comp_last_name, u1.options FROM (
SELECT u.record_id, u.first_name, u.last_name, GROUP_CONCAT(pv.poll_id,'.', pv.option_id ORDER BY pv.poll_id, pv.option_id) options
FROM users u
INNER JOIN poll_votes pv ON pv.user_id = u.record_id
GROUP BY u.record_id
) u1
INNER JOIN (
SELECT u.record_id, u.first_name, u.last_name, GROUP_CONCAT(pv.poll_id,'.', pv.option_id ORDER BY pv.poll_id, pv.option_id) options
FROM users u
INNER JOIN poll_votes pv ON pv.user_id = u.record_id
GROUP BY u.record_id
) u2 ON u1.options = u2.options AND u1.record_id <> u2.record_id
WHERE u1.record_id = 1;
The two inner queries are identical, and could actually be turned into a view. The outer query simply joins the two on the question / answer lists to get the matches.