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.
Related
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
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 the following database:
user_id and contact_id from Contacts table are PK and FK to the user_id field in the Users table. How can i select all contacts (or friends) of a specific user including the number of contacts of all contacts of this user. I tried different SELECT queries but either the number of contacts is incorrect or the contact_status is printed wrong. I use COUNT() as a function to print the number of contacts. I use this query but the contact_status is printed wrong:
SELECT COUNT(Contacts.contact_id), Users.user_id, Users.user_name, Users.name, Users.user_picture, Users.mood_message, Users.phone_number, Users.email, Users.country, Users.city, Users.website, Users.birth_date, Users.gender, Users.language, Users.about_me, Users.online_status, Users.privacy, Contacts.contact_status
FROM Contacts JOIN Users ON Contacts.contact_id = Users.user_id
WHERE Users.user_name IN (
SELECT Users.user_name
FROM Users
WHERE Users.user_id IN (
SELECT Contacts.contact_id
FROM Contacts
WHERE Contacts.user_id = 12
)
)
GROUP BY Users.user_name;
Users Table:
user_id, user_name, ...
12 John ...
13 Matt ...
14 Jack ...
Contacts Table:
user_id, contact_status, contact_id
12 1 13
13 1 12
12 2 14
If i want to print all Contacts of John the result should consist:
COUNT(Contacts.contacts_id), Users.user_name, Users. ... , Contacts.contact_status
1 Matt ... 1
0 Jack ... 2
The above query prints 1, 1 as a contact_status instead of 1, 2.
Can you help me with this query? Thanks in advance.
If I understood what's your goal, this should work:
SELECT c.contact_status, cc.contactCount, u.*
FROM Contacts c JOIN Users u ON (c.contact_id = u.user_id)
JOIN (
SELECT user_id, COUNT(1) contactCount FROM Contacts
GROUP BY user_id
) cc ON (c.user_id = cc.user_id)
WHERE c.user_id = 12
I hope I understand ur requirements, but its much simpler to use a subquery, like so:
SELECT
u.* -- Whatever fields you need
,(
select count(*) from Contacts c
where c.contactid = co.userid -- refers to outer record
) as contact_count
FROM
Users u Inner Join Contacts co
on co.UserId = u.UserId
WHERE
U.UserId = 12
I have 3 tables in my mysql DB to query.
Users_rates (fields: id,userid,raterid,rate,eventid) containing all of the rates(rate) that have been assigned to users(userid), participating to specific events(eventid), by other users(raterid)
Events_participants (fields:id,userid,eventid) containing all of the users(userid) participating to each event(eventid)
Users (fields:id,name,lastname)containing all the user relative data
I need to query those three tables to retrieve an event-specific rank for the users' rates.
Ex. John,Erik and Mark participated to 'eventid=31'.
John received 1 rate from Mark, and 2 from Erik.
Mark received 1 rate from Erik.
Nobody has rated Erik though.
I need to retrieve for each user name,lastname and the sum of the rates received for eventid=31
I tried with this:
SELECT events_participants.userid,users.name,users.lastname,
(SELECT SUM(rate)FROM users_rates WHERE users_rates.eventid=31 AND users_rates.userid=events_participants.userid)AS rate
FROM(( events_participants INNER JOIN users ON events_participants.userid=users.id)
LEFT OUTER JOIN users_rates ON events_participants.userid=users_rates.userid )
WHERE events_participants.eventid=31
But I receive:
userid | name | lastname | rate
1 | luca | silvestro | 1
3 | claudio | buricchi | 6
3 | claudio | buricchi | 6
What's the right query?
Thanks
Luca
Try this:
SELECT users.userid, users.name, users.lastname, temp.sum as rate
FROM users LEFT JOIN (
SELECT userid, SUM(rate) as sum FROM users_rates WHERE eventid = 31 GROUP BY userid
) as temp USING (userid)
It might give an error, this might work instead:
SELECT users.userid, users.name, users.lastname, temp.sum as rate
FROM users, (
SELECT userid, SUM(rate) as sum FROM users_rates WHERE eventid = 31 GROUP BY userid
) as temp WHERE users.userid = temp.userid
I don't know if I got the problem right, but maybe something like:
SELECT u.id, u.name, u.lastname, SUM(ur.rate) AS rate
FROM users AS u
INNER JOIN users_rates AS ur ON ur.userid = u.id
WHERE ur.eventid = 31
GROUP BY u.id
edit: If you want to receive a list with all users regardless of whether they have any rates at all, you could also join the users_participants table and replace the INNER JOIN of users_rates by a LEFT JOIN. The WHERE clause has to reference events_participants then (not users_rates anymore as it could be NULL):
SELECT u.id, u.name, u.lastname, SUM(ur.rate) AS rate
FROM users AS u
INNER JOIN events_participants AS ep ON ep.userid = u.id
LEFT JOIN users_rates AS ur ON ur.userid = u.id AND ur.eventid = ep.eventid
WHERE ep.eventid = 31
GROUP BY u.id