MySQL selecting tables where user exists - mysql

Let's say I have a mySQL table called "user" that contains a userid and a password or something. Then I have other tables for different purposes, such as a table for their favorite food, which would contain their userid and favorite food.
Is there a way to query for tables that contains a specified userid and checks whether they have an entry in that table?
So if I have three tables called favorite_food, favorite_drink, and favorite_candy, but userid only had values in favorite_food and favorite_drink, I want the query to return favorite_food and favorite_drink.
I'm a beginner and I couldn't quite grasp the concept of linking. Userid is the primary key of user and the other tables reference it?

Read more about UNION. I think that this is what you need.
SELECT * from favorite_food where `userid` = 50
UNION
SELECT * from favorite_drink where `userid` = 50
UNION
SELECT * from favorite_candy where `userid` = 50

In SQL "linking" is represented by JOINs. Since (as you indicated) some users will not have 1 or 2 favorite objects we will need to use LEFT OUTER JOINs. Then we will have NULLs in the output in place of missing favorites.
In your case:
SELECT u.userid, f.food_name, d.drink_name, c.candy_name
FROM user u
LEFT JOIN favorite_food f ON u.userid=f.userid
LEFT JOIN favorite_drink d ON u.userid=d.userid
LEFT JOIN favorite_candy c ON u.userid=c.userid
ORDER BY u.user.id
This will give you favorites for all users in your user table.

Related

delete from multiple tables

I have a table of users
user id
3 ,Frank
4 ,Steve
5 ,Joe
and a table of roles where column 1 is id of users in above table:
1, billing
3, Admin
2, Admin
4, user
5, billing
as you can see users 1 and 2 has been orphaned, and there is no user with id of 2. how can i delete this entry from the roles table? there could be dozens of entries in roles that dont have a user.
will this work?
DELETE from roles,users where roles.userId!==users.userId
You don't need to delete from users if the user is not there. So you can just do:
delete r from roles r
where not exists (select 1 from users u where u.userId = r.userId);
As mentioned in a comment, if you declared the roles.userId value to be a foreign key reference, then the database would not let this happen. After the data is fixed, you can do:
alter table roles add constraint foreign key (userId) references user(userId);
DELETE FROM roles WHERE id NOT IN (SELECT id FROM users)
Q: Will this work?
A: Close, but no cigar. No, the statement in the question won't perform the specified operation.
First, write a query to identify the orphaned rows. An anti-join pattern is a common approach (though there are several other workable approaches):
SELECT r.*
FROM `roles` r
LEFT
JOIN `user` u
ON u.id = r.user_id
WHERE u.id IS NULL
This uses an "outer" join, to return all rows from roles, along with matching rows from user. If no matching row is found in user, the columns from the user table will be returned as NULL. Given the equality comparison in the join predicate (ON clause), we know that all matching rows will have a non-NULL value for u.id. The "trick" is the predicate in the WHERE clause that excludes all rows that found a match, so we are left with rows in roles that don't have a matching row in users
(If you want to examine the rows that will be deleted and/or create a "backup" of those rows, this query gives you that.)
Next, convert the SELECT statement into a DELETE statement. For this particular statement, it's very straightforward with MySQL. The only change required is to replace the SELECT keyword with the DELETE keyword:
DELETE r.*
FROM `roles` r
LEFT
JOIN `user` u
ON u.id = r.user_id
WHERE u.id IS NULL
This is an example of just one of several workable approaches.

Fetching datasets from crosslinked table in a single query

Imagine the following MySQL table environment:
admins
id username
usergroups
id groupName
adminXusergroup (crosslinking table)
id adminId groupId
adminId and groupID are indexed and foreign key relations are configured accordingly (adminId points to admins.id and groupId points to usergroups.id).
All id fields are the primary keys.
I would like to retrieve all datasets from usergroups that correspond to a specific user in admins.
I have managed to do this in PHP by first fetching the according rows from adminXusergroup and then creating a list of IDs to select from admins in a second call. But even though it works, i feel like it can be optimized further, possibly by fetching all required information in a single MySQL query (joins perhaps?).
How can i fetch all datasets from usergroups that correspond to a specific dataset in admins (based on the id) by incorporating the information in the crosslinking table adminXusergroup ?
My current approach started like this:
SELECT * FROM usergroups WHERE usergroups.id=(SELECT id FROM adminXusergroup WHERE adminId="1");
But it doesn't seem right, and i am not sure as to how to apply nested selects in such a case?
I think you can achieve this using IN condition
SELECT *
FROM usergroups
WHERE usergroups.id IN
(
SELECT id
FROM adminXusergroup
WHERE adminId=1
);
Otherwise you can use an INNER JOIN query
SELECT *
FROM usergroups a
INNER JOIN adminXusergroup b
ON a.id = b.groupId
WHERE b.adminId = 1
Try This
SELECT a.id,u.*,x.* FROM admin as a
INNER JOIN usergroups as u on a.id=u.id
INNER JOIN adminXusergroup as x ON x.id=u.id WHERE u.id='userid'

SQL Server 2005/2008 : find row values that exist and list that don't in my in select column condition IN()

I have a single table that contain columns:
UserID, EmployeeID, BadgeType, HiredDate, TermDate
Now I need to find userID that are with (gbro, qunro, 1utny, ybeiot, 4ybey)
The 3 users (gbro, qunro, 1utny) exist so it is listed with respective its column info.
What if ybeiot, 4ybey does not exist AT ALL but still I want them listed in a separate table still but with a message that PRINTS: User that does not exist: ybeiot;4ybey
Help, been finding way how to do this.
I tried JOIN (all the joins) but it does not result to what I wanted.
Did you look at SQL EXISTS keyword?
put all the users to be searched in a temp table or table variable #userstoSearch
select * from #userstoSearch us left join users u
on us.UserID=u.UserID where u.userID is not null
select us.UserID from #userstoSearch us left join users u
on us.UserID=u.UserID where u.userID is null
for xml path('')
You need two selects. The first will list the existing values and the second lists the not existing values. You should merge these results using the union keyword.

Amount of users in a group where one particular user is present mysql

I'm trying to optimize this query but I can't seem to get it. Any help is more than welcomed. This is inside a stored procedure, so the 1 is replaced by an IN parameter.
Table userGroupRelation
userGroupID BIGINT --> foreign key to userGroupID in groups table
userID BIGINT --> foreign key to the users table
Table folders
ownerID BIGINT --> foreign key to the users table
postersGroup BIGINT --> foreign key to userGroupID in groups table
other stuff ...
SELECT folders.*,COUNT(userGroupRelation.userID) AS users
FROM folders
LEFT JOIN userGroupRelation
ON folders.postingGroupID = userGroupRelation.userGroupID
WHERE folders.ownerID = 1
OR userGroupRelation.userGroupID IN (
SELECT userGroupID FROM userGroupRelation WHERE userID = 1)
GROUP BY folders.folderID;
I basically want to get all the folders a user can see (either because he owns it or because he is in a group of posters for that folder)
I suggest two approaches. One is similar to your own, but removing the subquery and correcting the COUNT clause. I should mention it is unclear from your question whether the COUNT ... AS users result is of importance here, since you only specified you want to get all folders for a user.
SELECT
folders.*,
COUNT(DISTINCT IFNULL(userGroupRelation.userID, folders.ownerID)) AS users
FROM
folders
LEFT JOIN userGroupRelation ON folders.postingGroupID = userGroupRelation.userGroupID
WHERE
folders.ownerID = 1
OR userGroupRelation.userID = 1
GROUP BY
folders.folderID
;
This is somewhat better than your own solution because the subquery is eliminated, but it still leaves with this OR condition which is difficult to optimize -- it works on two different tables.
Edit: this next solution neither answers the question nor does it work at all :(
A completely different approach is to start with the users table (assuming you have one, of course):
SELECT
folders.*
FROM
users
LEFT JOIN folders ON (folders.ownerID = users.id)
LEFT JOIN userGroupRelation ON (userGroupRelation.userId = users.id)
LEFT JOIN folders ON (folders.postingGroupID = userGroupRelation.userGroupID)
WHERE
users.id = 1
GROUP BY
folders.folderID
;
This one is far better optimized if you have proper indexes on users.id and all joining columns. However:
It will not tell you the amount of (other) users per folder
SELECT filders.* .... GROUP BY filders.folderId is not strictly valid SQL -- though it will work if you're not using strict sql_mode. From you own query I can see you're not, so I won't dwell into that.

MYSQL: SELECT users from one user group and exclude users from another group - optimisation

I have an optimisation question here.
Background
I have a 12000 users in a user table, on record per user. Each user can be in zero or more groups. I have a groups table with 45 groups and a groups_link table with 75000 records (to facilitate the many to many relationship).
I am making a querying screen which allows a user to filter users from the user list.
Aim
Specifically, I need help with: Selecting all users that are in one group but are not in another group.
DB Structure
Query
My current query which runs too slowly...
SELECT U.user_id,U.user_email
FROM (sc_module_users AS U)
JOIN sc_module_users_groups_links AS group_join ON group_join.user_id = U.user_id
LEFT JOIN sc_module_users_groups_links AS excluded_group_join ON group_join.user_id = U.user_id
WHERE group_join.group_id IN (27) AND excluded_group_join.group_id NOT IN (19) OR excluded_group_join.group_id IS NULL AND U.user_subscribed=1 AND U.user_active=1
GROUP BY U.user_id,U.user_id
This query takes 9 minutes to complete, it returns 11,000 records (out of 12,000).
Explain
Here's the explain on that query:
Click here for a closer look
Can anyone help me optimise this to below the 1 minute mark...?
After 3 revisions, I changed it to this
SELECT U.user_id,U.user_email FROM (sc_module_users AS U) WHERE ( user_country LIKE '%australia%' ) AND
EXISTS (SELECT group_id FROM sc_module_users_groups_links l WHERE group_id in (31) AND l.user_id=U.user_id) AND
NOT EXISTS (SELECT group_id FROM sc_module_users_groups_links l WHERE group_id in (27) AND l.user_id=U.user_id)
AND U.user_subscribed=1 AND U.user_active=1 GROUP BY U.user_id
'
mucccch faster
EDIT: removed my query suggestion but the index stuff should still apply:
The indexes on the sc_module_users_groups_links could be improved by creating a composite index just on user_id and group_id. The order of the columns in the index can have an impact - i believe having user_id first should perform better.
You could also try removing the link_id and just using a composite primary key since the link_id doesn't seem to serve any other purpose.
I believe the very first thing you need to do is to place parentheses:
// should be
.. AND ( excluded_group_join.group_id NOT IN (19)
OR excluded_group_join.group_id IS NULL) AND ....