Query to fetch user names according to a condition from another table (SQL) - sql

I have two tables:
user
id
full_name
is_admin
is_active
1
Alan
0
1
2
Carl
0
1
3
Any
0
1
4
Jane
0
1
5
Marry
0
1
6
Pedri
0
1
7
admin
1
1
8
Mota
0
0
approver
id
subordinate_id
leader_id
main_leader_id
is_active
1
1
2
3
0
2
4
5
6
1
3
1
2
4
0
(subordinate_id, leader_id and main_leader_id are foreign keys that correspond to the id column of the user table)
I would like to perform a query that brings all user names that are not admin (user table is_admin=0) and that are active (user table is_active=1), and that if they have the id in the subordinate_id column in the approver table that only brings the name of that user that has the is_active of the approver table = 0.
That is, I would like to bring users that if they have any record as subordinate_id that only bring me those that are not active in the approver table.
I tried to get the data in the following way:
SELECT
full_name
FROM user AS U
LEFT JOIN approver AS A
ON U.id = A.subordinate_id
WHERE
A.id is null
AND
U.is_admin = 0
AND
U.is_active = 1
But with this query i only get the user name that not has a register in the approver table,
and in my case i want to get the user that have a register in the approver table as subordinate_id, but not if the register have the column 'is_active' equal to 1.
In my final result I could get something like this:
Alan
carl
any
marry
Pedri

In order to make this working, you should split the conditions in the WHERE clause into:
"user" conditions: is_admin = 0 AND is_active = 1
"approver" conditions: is not a subordinate OR is_active = 0
These two groups of conditions have to be set in AND.
SELECT DISTINCT user_.id, user_.full_name
FROM user_
LEFT JOIN approver
ON user_.id = approver.subordinate_id
WHERE (user_.is_admin = 0 AND user_.is_active = 1)
AND (approver.id IS NULL OR approver.is_active = 0)
Check the demo here.
Note: the DISTINCT keyword is necessary because the JOIN operation is made between two tables having cardinality 1:n.

Related

How to check the count of each values repeating in a row

I have two tables. Data in the first table is:
ID Username
1 Dan
2 Eli
3 Sean
4 John
Second Table Data:
user_id Status_id
1 2
1 3
4 1
3 2
2 3
1 1
3 3
3 3
3 3
. .
goes on goes on
These are my both tables.
I want to find the frequency of individual users doing 'status_id'
My expected result is:
username status_id(1) status_id(2) status_id(3)
Dan 1 1 1
Eli 0 0 1
Sean 0 1 2
John 1 0 0
My current code is:
SELECT b.username , COUNT(a.status_id)
FROM masterdb.auth_user b
left outer join masterdb.xmlform_joblist a
on a.user1_id = b.id
GROUP BY b.username, b.id, a.status_id
This gives me the separate count but in a single row without mentioning which status_id each column represents
This is called pivot and it works in two steps:
extracts the data for the specific field using a CASE statement
aggregates the data on users, to make every field value lie on the same record for each user
SELECT Username,
SUM(CASE WHEN status_id = 1 THEN 1 END) AS status_id_1,
SUM(CASE WHEN status_id = 2 THEN 1 END) AS status_id_2,
SUM(CASE WHEN status_id = 3 THEN 1 END) AS status_id_3
FROM t2
INNER JOIN t1
ON t2.user_id = t1._ID
GROUP BY Username
ORDER BY Username
Check the demo here.
Note: This solution assumes that there are 3 status_id values. If you need to generalize on the amount of status ids, you would require a dynamic query. In any case, it's better to avoid dynamic queries if you can.

2 resources relation - select each record for each record - even if pivot doesn't define it

I have 2 resources: users and privileges - and there is also some connecting table like user_privilege
So my structure looks like this:
user
user_id, name
1 John
2 Daniel
3 Paul
privilege
privilege_id, name
1 Perm 1
2 Perm 2
3 Perm 3
user_privilege
user_id, privilege_id
1 1
1 2
2 1
And if there is record in user_privilege that means user has this privilege.
But I also want to select privileges which user doesn't have.
It's easy to select all given privileges
But I want output like:
privilege_id, user_id, has
1 1 true
2 1 true
3 1 false
1 2 true
2 2 false
3 2 false
1 3 false
2 3 false
3 3 false
So actually it's something like each privilege for each user - but with information if user has this privilege or not.
I want to to this in Posgres db.
You want a cross join between user and privilege and then do an outer join to user_privilege to test if that user has the privilege
select au.user_id, au.privilege_id,
up.privilege_id is not null as has_priv
from (
select u.user_id, p.privilege_id
from "user" u
cross join privilege p
) au
left join user_privilege up on (au.user_id, au.privilege_id) = (up.user_id, up.privilege_id)
order by user_id, privilege_id
Online example

How to apply a single query that sum column for individual values

I have 2 tables named user and statistics
user table has 3 columns: id, name and category
statistics table has 3 columns: id, idUser (relational), cal
something like this:
user
Id name category
1 name1 1
2 name2 2
3 name3 3
statistics
Id idUser cal
1 1 1
2 1 1
3 1 1
4 2 1
5 2 1
How can I apply a query that sum the cal column by each category of users and give me something like this:
category totalcal
1 3
2 2
3 0
You want to do a left join to keep all the categories. The rest is just aggregation:
select u.category, coalesce(sum(s.cal), 0) as cal
from users u left join
statistics s
on u.id = s.idUser
group by u.category;
Use LEFT JOIN to get 0 sum for the category=3:
SELECT
user.category
,SUM(statistics.cal) AS totalcal
FROM
user
LEFT JOIN statistics ON statistics.idUser = user.Id
GROUP BY
user.category
Here SUM would return NULL for category=3. To get 0 instead of NULL you can use COALESCE(SUM(statistics.cal), 0).

Matching two variables to create a new ID

I'm trying to create an SQL statement to match either an id number or a postcode and then assign a new id number
What I want to end up with is ‘newid’ that correctly recognizes that the first four records are the same person (even though the postcode for record 2 is different).
record id postcode newid
--------------------------
1 1 1 1
2 1 2 1
3 1 1 1
4 2 1 1
5 3 3 2
Any suggestions would be appreciated greatly.
Going based on your example:
SELECT RECORD,
(SELECT MIN (ID)
FROM users u2
WHERE users.id IN (u2.id, u2.postcode)
OR users.postcode in (u2.id, u2.postcode)
) AS newid
FROM users
This results with the following data:
RECORD NEWID
------------------
1 1
2 1
3 1
4 1
5 3
Here is the SQLFiddle

Aggregate list of users and values into a table with list of users and counts of values

I have a table of users with three columns.
Username Accepted Rejected
User 1 1 NULL
User 1 1 NULL
User 1 NULL 1
User 2 1 1
User 3 1 NULL
User 3 1 NULL
User 2 NULL 1
User 3 NULL NULL
User 2 NULL NULL
I'd like to show a list of all the users with counts of Accepted/Rejected columns like so:
Username Accepted Rejected
User 1 2 1
User 2 1 2
User 3 2 NULL
What is the best way to do it?
If Accepted and Rejected can contain 1, 0 and null only use sum because sum will return null if all values supplied are null:
select UserName,
sum(Accepted) Accepted,
sum(Rejected) Rejected
from ATable
group by UserName
Count will return zero in Rejected column of user3.
SELECT
u.username,
CASE
WHEN COUNT(u.accepted) = 0 THEN NULL
ELSE
COUNT(u.accepted)
END AS Accepted,
CASE
WHEN COUNT(u.rejected) = 0 THEN NULL
ELSE
COUNT(u.rejected)
END AS Rejected
FROM
usr1 u
GROUP BY u.username