How can I add multiple rows referring to another table? - mysql

Let's say I have two tables like below:
users table:
user_id
name
0
kevin
1
alice
2
jake
3
mike
permissions table:
user_id
permission
1
12
1
5
3
1
And let's say that I want to add permission 5 to every single user who doesn't already have it. What would be the best MySQL query for this?

Your question is not 100% clear whether you only need a query or you want to do inserts. Anyway, this query with NOT EXISTS can be used as base for all necessary actions:
SELECT user_id, 5 AS permission
FROM users u
WHERE NOT EXISTS
(SELECT 1 FROM permissions
WHERE permission = 5 AND user_id = u.user_id);
This will list all user id's that haven't yet a permission 5 and as second column, just 5 will be selected as permission.
Then this result can be used for whatever it should be used. For example to add this outcome in a query to the already present entries, UNION ALL can be used:
SELECT user_id, 5 AS permission
FROM users u
WHERE NOT EXISTS
(SELECT 1 FROM permissions
WHERE permission = 5 AND user_id = u.user_id)
UNION ALL
SELECT user_id, permission
FROM permissions
ORDER BY user_id, permission;
If - and I think this is your real question - the result of the NOT EXISTS query should be inserted into the permissions table, this insert command will do this:
INSERT INTO permissions
(SELECT user_id, 5
FROM users u
WHERE NOT EXISTS
(SELECT 1
FROM permissions
WHERE permission = 5 AND user_id = u.user_id));
You can try out these things here: db<>fiddle

Below query will look for missing user id in permissions and insert new records in permissions table with a default permission equal to 5.
INSERT INTO permissions
(
user_id,
permission
)
SELECT user_id,
5 AS permission
FROM users
WHERE user_id NOT IN
(
SELECT user_id
FROM permissions)
)
Sample result:
user_id
permission
1
12
1
5
3
1
0
5
2
5

Related

Fetch users which have only status = 1 - Mysql query on same column

I want a list of user_id which shouldn't have zero status.
Lets say, I have task table with user id, status. I'm trying to write a query to fetch user ids which have status = 1 only but not 2. As for below table, it should get me users id of tables with only status =1;
User table
id
etc
100
anything
200
anything
300
anything
Tasks table:
id
user_id
status
1
100
1
2
100
2
3
200
2
4
300
1
5
200
2
6
300
1
I have tried this query
SELECT user_id FROM tasks where status =2 and status != 1;
The above user id 100 has two tasks one with status 1 and other with status 2, I don't want that user.
The above user id 200 has two tasks but none of them has status 1, that is what i want.
The above user id 300 has both tasks with status 1, I don't want it too.
Status 1 means open. So I want a query which should get me users with zero open tasks only. If it has status 1 and 2 both, I don't want that.
I have tried multiple queries, but unable to find it.
Using sub queries with IN()/NOT IN() you can build a list of users having tasks in status 1/2 and filter your users based on those lists:
SELECT *
FROM users
WHERE
-- ensure the user has at least 1 task in status 1
id IN(
SELECT user_id
FROM tasks
WHERE status = 1
)
-- ensure the user has no task in status 2
AND id NOT IN(
SELECT user_id
FROM tasks
WHERE status = 2
)
I have task table with user id, status. I'm trying to write a query to fetch user ids which have status = 1 only but not 2
SELECT *
FROM users
WHERE EXISTS ( SELECT NULL
FROM tasks
WHERE users.id = tasks.user_id
AND statis IN (1) -- must have 1
)
AND NOT EXISTS ( SElECT NULL
FROM tasks
WHERE users.id = tasks.user_id
AND statis IN (2) -- must not have 2
)
To test multiple values put according list to according WHERE .. AND statis IN (..) list.

How to find the dependency that brought another dependency in MySQL or Redshift

There is two tables:
dependency_permission table:
id
dependency_permission_id
2
1
4
2
user_permission table:
id
user_id
permission_id
1
11111
1
2
22222
4
3
22222
2
4
11111
2
5
33333
2
I want to write a query that finds all user_id's which have permissions depend on another permission the user doesn't have.
from the above data, users (22222 and 33333) should be returned, they don't have permission 1 which 2 depends on.
You may left join the 'user_permission' table with the 'dependency_permission' to get the 'dependency_permission_id' for each user 'permission_id', then use NOT EXISTS operator to check the existence of 'dependency_permission_id' for each user 'permission_id'.
with user_dependency_permission as
(
select U.user_id, U.permission_id, D.dependency_permission_id
from user_permission U left join dependency_permission D
on U.permission_id = D.id
)
select user_id, permission_id /* if you want to select only user_ids use distinct user_id*/
from user_dependency_permission T
where not exists(
select 1 from user_dependency_permission D
where T.user_id=D.user_id and
D.permission_id=T.dependency_permission_id
)
and T.dependency_permission_id is not null
See a demo on MySQL.

Query two tables where one of them has been transposed

I have the following tables, USER and RECORDS. The USER table simply has the name of the user and the group they have access to. If a user has null as their group (such as BOB does), that means they are a super user and have access to all the groups.
USER:
username | group
---------|--------
Bob | (null)
Kevin | 1
John | 2
Mary | 1
I then have a RECORDS table that has a list of records:
record | field_name | value
----------------------------
1 AGE 92
1 HEIGHT 9'2
1 __GROUP__ 1
2 AGE 11
2 HEIGHT 1'1
2 __GROUP__ 2
3 AGE 68
3 HEIGHT 6'8
This is not my design but it is what I have to query on. In the RECORDS table, the group that a record belongs to is indicated by the __GROUP__ value in the field_name column. So what I am trying to do is get a list of all the records each user has access to.
So based on the user table:
BOB has access to all the records
KEVIN and MARY only have access to records who have a field_name =
'__ GROUP __' and value = 1
JOHN only have access to records who have a field_name = '__ GROUP __'
and value = 2
This means
BOB has access to records 1, 2, and 3.
Kevin has access to only record 1
Mary has access to only record 1
John only has access to record 2
If the GROUP is missing from a record that means only a super user ( a user with group = null) can access it.
I understand if in the RECORDS table it would have a "GROUP" column this would be easier, but unfortunately, this isn't my database and I cannot make changes to the structure.
**Sorry, I forgot to mention it is possible for a user to be in multiple groups! For instance, Mary could be in groups 1 and 2.
One option uses exists:
select u.*, r.*
from user u
cross join records r
where u.grp is null or exists (
select 1
from records r1
where
r1.ecord = r.record
and r1.field_name = '__GROUP__'
and r1.value = u.grp
)
This gives you the entire records rows that each user has access to.
If you just want the list of record ids, you can use aggregation instead:
select u.userame, r.record
from users u
cross join records r
group by u.userame, u.grp, r.record
having
u.grp is null
or max(r.field_name = '__GROUP__' and r.value = u.grp) = 1

Adding a row if it does not exist in a MySQL table

Inside a table there are 2 columns: userid and roleid. Every user should atleast have roleid 4 . There are currently around 10.000 records, but somehow a small amount of users do not have this role.
Visual example:
userid | roleid
1 1
1 4
2 1
2 4
3 1 <---------- userid 3 misses roleid 4!
4 1
4 4
Is it possible to execute a query and add a row with the userid and roleid when that combination does not exist?
Yes.
insert into userRoles(userid, roleid)
select userid, 4
from userRoles
group by userid
having sum(roleid = 4) = 0;
The sum(role = 4) in the having clause counts the number of rows for each user that have 4. The = 0 says there are none.
Note: This gives all users in this table a role id of 4. There may be users with no roles at all.
If you want them, then use the users table:
insert into userRoles(userid, roleid)
select u.userid, 4
from users u
where not exists (select 1 from userRoles ur where ur.userid = u.userid);
You should search for user that have not 4 in roleID
insert into yourTable ( userId, roledid)
select userid, 4
from yourTable
where roleid <>4

Mysql show different columns for different where clauses

I want to show a output table that counts all the users found in a table.
Basically I want the output to look like:
+-----------+-----------+
| user1 | user2 |
+-----------+-----------+
| 5 | 2 |
+-----------+-----------+
I'm just using a dummy table to test this. My query looks like this:
(
select
name as user1
from
users
where
name = 'root'
) UNION (
select
name as user2
from
users
where
name = 'not_root'
)
Which only outputs something like this:
+-----------+
| user1 |
+-----------+
| 5 |
| 2 |
+-----------+
EDITED
The main idea of the approach it's treat a table as two different virtual tables in subquery. We can make nested select statement e.g. (select count(*) as c from users where name = 'root') u1 MySql treats it as particular table named u1 with one row and one column named c.
select u1.c as root_cnt, u2.c as not_root_cnt
from (select count(*) as c from users where name = 'root') u1,
(select count(*) as c from users where name = 'not_root') u2
or
Moreover if you have select statement that returns only one row you can put nested selects directly in fields list
select (select count(*) as c from users where name = 'root') as root_cnt, (select count(*) as c from users where name = 'not_root') as not_root_cnt
Definite disadvantage of such approach it's extra subqueries. Method based on using case when construction free from such disadvantage.
Try this
SELECT
SUM(CASE WHEN Name = 'root' THEN 1 ELSE 0 END) user1,
SUM(CASE WHEN Name = 'not_root' THEN 1 ELSE 0 END) user2
FROM Users
You can use a case statement inside of count to get the counts in separate columns
select
count(case when name = 'root' then 1 end) user1,
count(case when name = 'not_root' then 1 end) user2
from users
where name in ('root','not_root')
It seems your query is wrong..
union won't combine the results of two queries in the way you have described above.
union would combine the result of two or more select statements but wouldn't "join" it.
You might want to use joins for this cause. still you wouldn't be able to put 5|2 in same row as it basically suggests --> fetch user 1 and user 2 values for one particular type
i think group by is a much better approach:
select user, count(user) from users group by user