MySQL find matching set of rows - mysql

I have a cross-reference table that supplies the many-to-many relationship between users and user group tables. It contains two relevant columns: group_id and user_id (surprise, surprise!). When a user wants to create a new group, I want to first check if that set of users already exists as a group.
Essentially I would define the problem as "Given a set of user ids, find any set of rows that match the set of user ids and all share the same group id".
Edit:
I'm looking for the exact set of users, not interesting in seeing in the resultset groups that include those users in addition to other users.
Sample Data
I have the hunch that a subquery is the way to go, but I can't figure out how to arrange it. Any help would be greatly appreciated!

Is this what you want?
select groupid
from usergroups ug
where userid in ($user1, $user2, . . . , $usern)
group by groupid
having count(*) = <n>;
This returns all groups that have the supplied list of users.
If you want the exact set, then:
select groupid
from usergroups ug
group by groupid
having count(*) = sum( userid in ($user1, $user2, . . . , $usern) );
This assumes that groups don't have the same user twice (it is not hard to adjust for that, but the condition becomes more complicated).

Related

MySQL query to find values in table with given value and find others that are similar

I have a table called followers and I want to be able to find the current users followers, display that list, and then compare those values against another user ID to see if they are following them or not from that same table
This is the table I'm using currently to get the list of followers for a specific user:
followers
-------
followId - primary key, the unique id for the follow relationship
userId - the user that is following someone
orgId - that someone that the user is following
I tried using a union query but I wouldn't want to due to performance reasons (table may contain high volume of records) and because it isn't scalable (I think)?
The expected output should be the list of orgId's for which the user(the user I am checking against) is following, and another column that shows whether my user(my userId that I provide) is following that orgId value (i.e a following column).
Hmmm, if I understand correctly, you have two users and you want to know which orgs followed by the first are also followed by the second:
select f.orgid,
(exists (select 1
from followers f2
where f2.userId = $seconduserid and
f2.orgid = f.orgid
)
) as seconduserflag
from followers f
where f.userId = $firstuserid

mysql NOT IN query

I am trying to produce a list of user that have access to particular locations. The table in my database that records locations users have access to is backwards in my opinion. It list the location the users can not access. I have tried not in several different ways without any luck. The query just returns a blank results set. I've tried find something on here to help me and googled it but this has not helped...I always get blank results screen(nothing returned). I think the issue lies with the USER_LOCATION_EXCLUSION having several entries for each USER_ID for each corresponding location. I did not create this table structure but inherited it.
Scenario
Tables Columns
====================================================
APP_USER USER_ID, USER_NAME
LOCATION LOCATION_ID, LOCATION_NAME
USER_LOCATION_EXCLUSION USER_ID, LOCATION_ID
APP_USER and LOCATION tables both have IDs that are unique. These IDs are both used in USER_LOCATION_EXCLUSION (list locations users can not access) and can be used many times in this table according to the users access. I would like to produce report that has the USER_NAME and LOCATION_NAME they have access to.
What it sounds like you want is a Cartesian result LESS the exclusions... ie: for each user, assume giving them EVERY location access, then find out what they are excluded from...
select
PreQuery.User_ID,
PreQuery.User_Name,
PreQuery.Location_Name
from
( select
AU.User_ID,
AU.User_Name,
L.Location_ID,
L.Location_Name
from
App_User AU,
Location L ) PreQuery
LEFT JOIN USER_LOCATION_EXCLUSION ULE
on PreQuery.User_ID = ULE.User_ID
AND PreQuery.LOCATION_ID = ULE.LOCATION_ID
where
ULE.Location_ID = NULL
By doing a LEFT JOIN to the exclusion table, every record will ATTEMPT to be joined to the exclusion list... So, when it DOES find a match, that location ID will exist... when it does NOT exist, it will be null (satisfying your NOT Excluded from)
This also eliminates sub-select WHERE clause tested for every user / location
I would use something like this. To obtain all combinations of locations-users you could use a Select query with no joins:
Select *
From Location, App_User
but from here you have to exclude combinations of locations-users that are included in user_location_list table. This can solve your problem:
Select
Location.*,
App_User.*
From App_USer, Location
Where
Not Exists (select * from user_location_exclusion
where user_location_exclusion.user_id=app_user.user_id
and user_location_exclusion.location_id=location.location_id)
This shows every location for every user that has not been excluded.

How do I select a record from one table in a mySQL database, based on the existence of data in a second?

Please forgive my ignorance here. SQL is decidedly one of the biggest "gaps" in my education that I'm working on correcting, come October. Here's the scenario:
I have two tables in a DB that I need to access certain data from. One is users, and the other is conversation_log. The basic structure is outlined below:
users:
id (INT)
name (TXT)
conversation_log
userid (INT) // same value as id in users - actually the only field in this table I want to check
input (TXT)
response (TXT)
(note that I'm only listing the structure for the fields that are {or could be} relevant to the current challenge)
What I want to do is return a list of names from the users table that have at least one record in the conversation_log table. Currently, I'm doing this with two separate SQL statements, with the one that checks for records in conversation_log being called hundreds, if not thousands of times, once for each userid, just to see if records exist for that id.
Currently, the two SQL statements are as follows:
select id from users where 1; (gets the list of userid values for the next query)
select id from conversation_log where userid = $userId limit 1; (checks for existing records)
Right now I have 4,000+ users listed in the users table. I'm sure that you can imagine just how long this method takes. I know there's an easier, more efficient way to do this, but being self-taught, this is something that I have yet to learn. Any help would be greatly appreciated.
You have to do what is called a 'Join'. This, um, joins the rows of two tables together based on values they have in common.
See if this makes sense to you:
SELECT DISTINCT users.name
FROM users JOIN conversation_log ON users.id = converation_log.userid
Now JOIN by itself is an "inner join", which means that it will only return rows that both tables have in common. In other words, if a specific conversation_log.userid doesn't exist, it won't return any part of the row, user or conversation log, for that userid.
Also, +1 for having a clearly worded question : )
EDIT: I added a "DISTINCT", which means to filter out all of the duplicates. If a user appeared in more than one conversation_log row, and you didn't have DISTINCT, you would get the user's name more than once. This is because JOIN does a cartesian product, or does every possible combination of rows from each table that match your JOIN ON criteria.
Something like this:
SELECT *
FROM users
WHERE EXISTS (
SELECT *
FROM conversation_log
WHERE users.id = conversation_log.userid
)
In plain English: select every row from users, such that there is at least one row from conversation_log with the matching userid.
What you need to read is JOIN syntax.
SELECT count(*), users.name
FROM users left join conversion_log on users.id = conversation_log.userid
Group by users.name
You could add at the end if you wanted
HAVING count(*) > 0

Summing multiple columns

user table
user_id
entry
user_id
points_a
points_b
SELECT user.*,
(SUM(entry.points_a) + SUM(entry.points_b)) as points_total
FROM user
LEFT JOIN entry on entry.user_id = entry.user_id
..is what I'm trying to do — get a total count of all points that a user has. The field type for points is INT. This Doesn't seem to work?
Given that you have no columns in user except the ID, the join really serves no purpose.
select userid, SUM(points_a) + SUM(points_b) as total
from entry
group by userid
This will give you what you are looking for. If you need more fields from the user table that you just didn't show, you can do the join and add those fields to the select.
I think what you were missing was the Group By clause though.

MySQL select where equal to multiple values

I have two databases, where I store who is following who and another which stores the posts the user makes.
I want to select all of the people a user is following from the following database and echo out the usernames of those who that user is following and query the posts database for posts of that user.
My problem is what if a user is following multiple users,
I echoed out of the user id's of the people this user is following and I get
44443344330
When I separate each id with commans, I get:
44,44,33,44,33,0,
so let's give that a variable of $user_ids;
$user_ids = "44,44,33,44,33,0, ";
the query:
$get_posts = mysql_query("SELECT * FROM posts WHERE userid = '$user_ids'");
but all it does is show the records of the first user id, 44.
How can I retrieve all of the records for all the users?
The query should be:
SELECT * FROM posts WHERE userid IN (44,44,33,44,33,0)
However, you may have to rethink your data model and make sure it is normalized, so that you can express this construction directly in the databse without echoing into a comma-separated string.
Why do you have two databases? Do you mean two tables?
Maybe you want to use IN
SELECT * FROM posts WHERE userid IN ($user_ids)
Given that you have two tables, not two databases, the easiest way to match multiple values for a specific column would be the following:
SELECT * FROM posts WHERE userid IN (44,44,33,44,33,0)
*A small point that I ran into when doing this. If you are matching to a column that is of type VARCHAR(n), be sure to wrap your matching values in 'single quotes', not "double quotes"
e.g:
SELECT * FROM posts WHERE name IN ('foo','bar','alpha','beta')
Assuming you have two tabels, not databases, and that the table (lets call it "friends") which describes who is following who is like
table friends(
userid
friendid
)
then query to get posts posted by X's friends would be
SELECT
p.*
FROM posts p
JOIN friends f ON(p.userid = f.friendid)
WHERE f.userid = X
$get_posts = mysql_query("SELECT * FROM posts WHERE userid in '($user_ids)'");
$var= str_replace(","," or userid = ","userid =$your_data_from_db");
your myqsl_query = SELECT * FROM posts where $var