Is it possible in one query to test if a number of users are in the same group or not?
say I have an array that looks like this:
$users = array(1,3,4,5);
I want to dynamically write a query (so that it can handle any number of users) that would essentially check if there is a group that contains all these users AND ONLY THESE USERS already in existence. If so, return the id. If not, return 0.
The table structure is as follows:
groups:
group_id
groups_users
user_id
group_id
Is that possible?
SELECT group_id, count(*) AS c
FROM group_users
WHERE user_id IN (1, 3, 4, 5)
GROUP BY group_id
HAVING c = ?; /* Replace ? with len($users) */
Assuming that groups_users.user_id and groups_users.group_id is a unique key, if this group exists, then the result of count(*) should be equal to len($users).
Related
Sql fidle here.
SELECT UserId,totalLikes FROM Users
LEFT JOIN(select ownerId, PostId from Posts) a ON ownerId = UserId
LEFT JOIN(select idOfPost, count(idOfPost) AS totalLikes from Likes) b ON idOfPost = PostId
WHERE UserId = 120 GROUP BY UserId
This is a simplified part of the query that i am using, on the fiddle it works exactly how i need it to, it counts every idOfPost as a like for every post that belongs to the user specified, in this case where UserId = 120
and it groups the result in a single row.
But when i run this in WAMP i am getting the following error #1140 this is incompatible with sql_mode=only_full_group_by witch i think is because i need to group by PostId as well, but if i do that i get multiple rows, naturally because the id of the posts are different but i want to have it in a single row.
So my questions are: Should i disable the sql_mode=only_full_group_by witch i'm not really sure what impact would have, or is my tables structure at fault and it needs to be changed, maybe including the UserId in the Likes table, or my query is at fault and needs to be changed?
mysql version 5.7.14 on WAMP
Use GROUP BY in the subquery and sum() aggregate in the main query:
SELECT UserId, sum(totalLikes) AS totalLikes
FROM Users
LEFT JOIN Posts a ON ownerId = UserId
LEFT JOIN (
select idOfPost, count(idOfPost) AS totalLikes
from Likes
group by idOfPost) b ON idOfPost = PostId
WHERE UserId = 120
GROUP BY UserId
SqlFiddle.
I have the following query:
SELECT DISTINCT * FROM group_members
INNER JOIN groups ON groups.group_id = group_members.group_id
WHERE group_members.user_id = *1* OR groups.created_by = *1*
However when it executes I get the following results:
Test - user 1
Test - user 2
But I want
Test - user 1, user 2
I can't seem to understand how to modify my query to produce this. Would anyone have an idea?
In essence, I am trying to query for all the groups the user has either created or is part of
Groups Schema:
group_id (primary key)
group_name
group_description
created_by
group_creation_date
Group_Members Schema
member_id (primary key)
group_id (foreign key)
user_id (foreign key - users table)
date_added
Those rows are distinct/different - so DISTINCT is doing it's job; it ensures there are no duplicate rows - that means that if you select multiple columns it ensures there are no duplicate combinations. It does not ensure that there are no duplicate values for the field immediately following it as I think you are expecting.
I think you probably want to look at using GROUP BY with GROUP_CONCAT?
https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
I'm not clear which fields you are trying to select - but something like:
Try:
SELECT *, GROUP_CONCAT(user_id)
FROM FROM group_members
INNER JOIN groups ON groups.group_id = group_members.group_id
WHERE group_members.user_id = *1* OR groups.created_by = *1*
GROUP BY group_id
What I need seems kind of complicated, but then again I'm not that good at SQL. Basically I have a table that stores conversation participants. I need a query that will, using two provided User IDs, determine if a conversation exists containing ONLY the two given users. Conversations containing additional users beyond just these two shouldn't be counted---only a single 1-on-1 conversation between the two given users.
Here is my SQLfiddle: http://sqlfiddle.com/#!9/284e1/33/0
And my in-progress query which isn't doing the trick:
SELECT *
FROM mybb_conversation_participants
WHERE conversation_id IN (
SELECT conversation_id
FROM mybb_conversation_participants
WHERE (user_id = 6 OR user_id = 11)
GROUP BY conversation_id
HAVING COUNT(*) = 2
);
I don't think I'm understanding the HAVING COUNT(*) = 2 part, because this query returns all conversations containing the two users, even if other users exist in that conversation as well. Again, only 1-on-1 conversations between the two provided users should be selected, otherwise the query should select nothing. For example, in the SQLfiddle above, only rows with a conversation_id of 12 or 19 should've returned, since all the other matches include more than two rows.
That is what I was hoping the HAVING statement would do, but apparently not.
Any ideas?
You can do this with group by and having:
SELECT conversation_id
FROM mybb_conversation_participants
GROUP BY conversation_id
HAVING SUM( (user_id NOT IN (6, 11) ) = 0;
What is this doing? It is aggregating by the conversation id. Then, for each conversation it counts the number of times a user is not one of the two. It accepts conversations where this is true.
If you prefer positivity, this might be easier to follow:
HAVING SUM( (user_id IN (6, 11)) = COUNT(*)
That is saying that all the users on the conversation are accounted for with the ones you have chosen.
Finally, if you want to be sure that both (all) are involved:
HAVING SUM( (user_id IN (6, 11)) = COUNT(*) AND
COUNT(DISTINCT user_id) = 2
Given two MySQL tables:
member: id, status, name, type
serial: id, serial, description
I want to select the IDs where member.status = "2" and serial = any serial where ID is a specified value.
So in other words, given an ID, I want to find the distinct serial numbers associated with an ID, then return ALL IDs that have that serial number - but only if their status is "2".
I don't think that I want a JOIN or a UNION. I probably want to select serial.id where serial=ANY(select serial where serial.id="value") - but I can't figure out how to require member.status = "2".
How should I do this?
Thanks.
I think the following should work. Use a subquery to find all serial numbers associated with a specified id, then find all ids whose serial is in the result of the subquery; put an inner join in the outer query to match status to id.
SELECT m.id
FROM member m
JOIN serial s
ON s.id = m.id
WHERE s.serial IN
(SELECT serial
FROM serial
WHERE id = :search_id) ids
AND m.status = '2';
I run a survey where all answers are stored in a separate row in the 'survey' table.
My table looks like this:
(ID,user_id,Q,A)
(1,10,'laundry','oxiclean')
(2,10,'laundry','tide')
(3,10,'laundry','pods')
(4,11,'laundry','spray n wash')
(5,11,'laundry','resolve')
(6,12,'laundry','oxiclean')
(7,13,'laundry','oxiclean')
I now need to pull the count of user id that selected ONLY specific products.
"SELECT *, count(user_id) FROM survey WHERE Q='laundry' GROUP BY a"
the above will give a an overall COUNT but I need to get my count based on users that selected ONLY 'oxiclean' for example. This should return 2.
Or users that selected 'oxiclean' AND 'tide' ONLY.
How do I go about performing this 'combination' of results pulled from different rows?
Thanks a lot!
select user_id from survey group by user_id having count(user_id) = 1
This retrieves a list of users which have only one answer in the survey. Use it as a filter condition:
select q,a,count(user_id)
from survey
where a = 'oxiclean'
and user_id in (select user_id from survey group by user_id having count(user_id) = 1)
You can achieve that using a subquery, for your case it will be something like that :
SELECT *, COUNT(user_id)
FROM survey AS s
WHERE Q = 'laundry'
AND A = 'oxiclean'
AND user_id NOT IN (SELECT user_id FROM survey WHERE Q = s.Q AND A != s.A);
s.Q and s.A refer to the parent field so you don't have to reinject the name a second time.
Downside : the query works only if you want one specific answer.
If you want one query to retrieve the overall count, this one should do the trick :
SELECT A, COUNT(user_id)
FROM (
SELECT A, user_id
FROM survey
WHERE Q='laundry'
GROUP BY user_id
HAVING COUNT(user_id) = 1
) AS t
GROUP BY A
Downside : the query give only answers who have only at least one unique user_id as seen here, and this syntax create a temporary table which is something to avoid for performance reasons.