How to select/match from MySQL table? - mysql

I have the following table:
People
---------
ID | Name
---------
1 | John
2 | Sam
And I have another table:
Permissions
-----------
ID | Perm
-----------
1 | View
2 | Edit
3 | Delete
These two tables are linked in a third table:
UserPermissions
----------------------
ID | User | Permission
----------------------
1 | 1 | 1 (View)
2 | 1 | 3 (Delete)
3 | 2 | 1 (View)
I am trying to select a "total" permissions type table, where, if I wanted to get the permission for a user (Lets say user 2 (Sam)), I would get the following table:
UserPermissions
------------------
Permission | User
------------------
1 (View) | 2
2 (Edit) | NULL (Or some other nullish value)
3 (Delete)| NULL
I have only recently started MySQL and I have no idea of what search terms I should be trying to get examples of similar queries. Does anyone know what type of queries I should be searching for / a way to implement this?

If you want to do this for one user, you want a left outer join:
select p.*, up.user;
from Permissions p left outer join
UserPermissions up
on p.Permission = up.Permission and
up.User = 2;
This works for one user.

Sounds like you're just looking for an OUTER JOIN:
SELECT P.Id, P.Perm, UP.Id User
FROM Permissions P
LEFT JOIN UserPermissions UP ON P.Id = UP.Permission

Related

Getting Display Name for UserID twice in same query

I have a table called Users:
UserID | DisplayName
----------------------
2 | Jack
3 | Jill
And a table called Tasks:
TaskID | UserID | UserForID
--------------------------------
1 | 2 | 3
2 | 3 | 2
3 | 3 | 3
Basically in here, users can set tasks for each other or themselves.
My query is as follows:
SELECT *
FROM Tasks
INNER JOIN Users
ON Tasks.UserForID=Users.UserID
Now using $row['DisplayName'] gets the display name of the user the task is for, but how do I go about getting the display name of the user who posted the task?
Join the same user table for both the users. When you joined for first time you joined based on UserForID thats why you were getting only for ForUser, now if you join
SELECT t.TaskID, u.DisplayName as ForUser, tu.DisplayName as FromUser
FROM Tasks t
INNER JOIN Users u ON t.UserForID=u.UserID
INNER JOIN Users tu ON tu.UserID=t.UserID
The key FromUser will contain the name of the user who created the task

Mysql: Show all users that a user is following and add dynamic column if i also follow that user

I have a website with a twitter-like follower system.
I have a mySQL-table "followers", like this:
'followers' TABLE STRUCTURE:
| user_id | follow_id |
--------------------------
| 1 | 2 |
| 1 | 3 |
| 2 | 3 |
| 2 | 4 |
Now I want to get all the users listed that f.e. user 2 is following (so 3 and 4) but I also want to show if the current user logged in (let's assume user 1) is also following a user. This information should be added dynamically to a new column "ifollow", like this:
Expected result when checking which users "user 2" is following:
| user_id | follow_id | ifollow |
---------------------------------------
| 2 | 3 | true |
| 2 | 4 | false |
Right now I just get all the users a user is following and then check in the view with a function like "doIFollow($id)" to display the right follow/unfollow-buttons but I think it would be way better to just get all the needed information with the query. Does anyone know how this ist possible?
You can use a correlated subquery for this:
SELECT user_id, follow_id,
COALESCE((SELECT true
FROM followers AS f2
WHERE f2.follow_id = f1.follow_id AND
f2.user_id = 1), false)
FROM followers AS f1
WHERE user_id = 2
Edit: (credit goes to #Mjh)
The same thing can also be accomplished with a simple LEFT JOIN operation:
SELECT f1.user_id, f1.follow_id,
IF(f2.user_id IS NULL, false, true) AS ifollow
FROM followers AS f1
LEFT JOIN followers AS f2
ON f1.follow_id = f2.follow_id AND f2.user_id = 1
WHERE f1.user_id = 2

How to join more than 2 tables in MySQL?

I have 3 tables i want to join all tables each other. But my 3rd table not working.
See my table -
users
id | username |is_active
----------|----------------|------------
1 | chinu | 1
2 | sradhanjali | 1
3 | User3 | 0
settings
id | user_id | public_msg_notification
----------|-----------|---------------------------
1 | 1 | 1
2 | 2 | 1
3 | 3 | 1
friends
id | user_id | friend_id | is_block
----------|-----------|---------------------------
1 | 3 | 1 | 0
2 | 1 | 2 | 1
3 | 3 | 2 | 0
Query
SELECT a.username FROM users a
JOIN settings b
JOIN friends c ON(a.id=c.user_id OR a.id=c.friend_id)
WHERE a.username IN('john','piter','rahul','sradhanjali')
AND a.id != '1' AND a.is_active=1
AND a.id=b.user_id AND b.public_msg_notification=1
AND c.is_block=0 GROUP BY a.username
I have run this query in my local only sradhanjali username fetched. But this user is_block=1 in the friends table.
I think My third table friends not working. I want to show that result those usernmes where is_block=0. In above data my output should be zero(0) But I am getting 1 record while execute above query.
We had a chat discussion and I think this question is not meant to be on SO for the most part. I did promise if I could figure it out I would try to provide some insight. At this point I think this is a correct approach, but it is very specific to this instance.
SELECT u.username FROM users u
JOIN (SELECT
IF(u.id=f.user_id, f.friend_id, f.user_id) as ids
FROM users u
JOIN friends f ON (f.user_id=u.id OR f.friend_id=u.id)
WHERE
u.id=$SOME_ID AND f.is_block=0) friends ON (u.id=friends.ids)
JOIN settings s ON (s.user_id=friends.ids)
WHERE s.public_msg_notification=1 AND u.is_active=1
GROUP BY friends.ids
By trying to be too specific you aren't able to open up the query any more and have to do a nested query inside. This should get all users you are friends with THEN see which users are accepting public notifications and are active. I'm fearing this will fail. But this at the least will put you in the right direction.

MYSQL selecting from two tables but the second table not always have relationship to the first

So I have two tables, one containing user info (Users), and the other containing info of which users not to show (Settings). So, I want to do a query that will show all the users in the users table except the ones listed in the settings. Thanks in advance.
Users
| id | name |
===============
| 1 | adam |
| 2 | alex |
| 3 | andrew|
Settings
| id | name | value | user_id |
===============================
| 1 | hide | 1 | 1 |
I want the results to be :
| id | name |
==============
| 1 | alex |
| 2 | andrew|
Something like:
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM settings WHERE name="hide");
would get only the users from the users table which are not in the settings table where the setting name equals "hide"
To get list of something present in one table, but not in another (related) one, you can either use the famouse LEFT JOIN-NULL combo:
SELECT u.id, u.name
FROM users AS u
LEFT JOIN settings AS s
ON s.user_id = u.id
WHERE s.user_id IS NULL
... or NOT IN clause on dependent sub-query:
SELECT u.id, u.name
FROM users AS u
WHERE u.id NOT IN (SELECT user_id FROM settings)
I usually use the first one, but according to this article, there should not be any significant speed difference between those. Anyway, I'd suggest benchmarking them on your specific DB instance, then choosing the best one.
SELECT * FROM users WHERE id NOT IN (SELECT * FROM settings)
try this
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM settings WHERE user_id='1');

Select all if no subset is present, otherwise select subset

Ok here's my problem. Assume a customer has access to a number of regions defined in a CustomerRegions table:
CustomerRegionID | CustomerID | RegionID
----------------------------------------
1 | 1 | 1
2 | 1 | 2
Assume that customer 1 has three users 1, 2, and 3. For each user we can specify to which of the CustomerRegions they have access via a table UserRegions:
UserRegionID | UserID | CustomerRegionID
----------------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 2
So user 1 will have access to both Customerregions and user 2 will only have access to CustomerRegion 2.
If there are UserRegions specified for a given user then only those CustomerRegions are present in the result set, but if no UserRegions are specified for a given user then all CustomerRegions are present in the result. I want to get all accessible regions per user of a given customer. The result I am looking for is something like this:
CustomerID | UserID | RegionID
------------------------------
1 | 1 | 1
1 | 1 | 2
1 | 2 | 2
1 | 3 | 1
1 | 3 | 2
My question is can this be done in a single query and how?
Edit:
I seem to have it working now:
SELECT CustomerID,
UserID,
RegionID
FROM users
LEFT JOIN customerregions ON customerregions.CustomerID = users.CustomerID
LEFT JOIN userregions ON userregions.UserID = users.UserID AND userregions.CustomerRegionID = customerregions.CustomerRegionID
LEFT JOIN regions ON regions.RegionID = customerregions.RegionID
WHERE (userregions.UserID IS NOT NULL
OR (SELECT COUNT(1) FROM userregions WHERE userregions.UserID = users.UserID) = 0)
AND CustomerID = 1
The extra count query in the where seems to do the trick. Thanks #Pablo Martinez for your help. However if someone knows of a better way to do this please let me know.
I'm aggre with #diEcho, the table structure is very confusing
have you try to do a join?
Select CustomerID, UserID, RegionID
from UserRegions join CustomerRegion
on CustomerRegion.CustomerRegionID=UserRegions.CustomerRegionID
where customerID=1