I have a dataset of users who have liked each other. The data looks like
User HasLiked
User 1 User 3
User 1 User 4
User 1 User 5
User 2 User 3
User 3 User 1
User 4 User 1
User 4 User 5
User 5 User 3
User 5 User 4
I can get count of liked users for any given user using
select user, count(*) as liked_count
from users
group by user;
which gives me
User liked_count
User 1 3
User 2 1
User 3 1
User 4 2
User 5 2
However I can't figure out how to count the number of times a user is liked back by someone they have liked. e.g what I want is:
User liked_count liked_back_count
User 1 2 2
User 2 1 0
User 3 1 1
User 4 2 2
User 5 2 1
Any ideas how to do this using sql? FYI, The number of distinct users is around 100K.
You can use a left join to determine if the "inverse" record appears. And then aggregate:
select u.user, count(*) as liked_count,
count(*) filter (where u2.user is not null) as liked_back_count
from users u left join
users u2
on u2.user = u.hasliked and
u2.hasliked = u.user
group by u.user;
Related
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.
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
My "users" table is like this
id name
1 UserA
2 UserB
3 UserC
4 UserD
And my "chats" table is like this
id text sentBy sentTo created
1 Hi UserB 1 2 2019-01-11
2 Hi 2 1 2019-01-12
3 Hi UserB 3 2 2019-01-13
4 Hello UserC 2 3 2019-01-14
5 Hello 3 2 2019-01-15
6 What u do 2 1 2019-01-16
7 Nothing 1 2 2019-01-17
8 Okay 2 1 2019-01-18
8 Hi UserA 3 1 2019-01-19
I want to show user list who is involved in a conversation with logged in user based on the last msg.
Like if UserA logged in the system then the list should be like
userId userName text created
3 UserC Hi UserA 2019-01-19
2 UserB Okay 2019-01-19
I tried by using a join query and group by but not succeed.
I am using PostgreSQL with koa js.
You may use DISTINCT ON to filter out all apart from the most recent record for each involved in the conversation.
SELECT DISTINCT ON( involved) involved AS userid,
u.NAME AS username,
text,
created
FROM (SELECT c.*,
CASE sentby
WHEN 1 THEN sentto
ELSE sentby
END AS involved
FROM chats c
WHERE c.sentby = 1
OR c.sentto = 1) s
JOIN users u
ON s.involved = u.id
ORDER BY involved,
created DESC
Demo
If you want a generic case, you may convert this to a SQL type Postgres function and pass userid as an argument and use it in place of 1.
To get a complete list of users involved in the last conversation of the $current_user, with the last message (sent or received) and its date (created):
WITH u1 AS (SELECT id FROM users WHERE name = $current_user)
SELECT DISTINCT ON (userId) *
FROM (
SELECT u.id AS userId, u.name AS userName, c.text, c.created -- received
FROM u1
JOIN chats c ON c.sentBy = u1.id
JOIN users u ON u.id = c.sentTo
UNION ALL
SELECT u.id, u.name, c.text, c.created -- sent
FROM u1
JOIN chats c ON c.sentTo = u1.id
JOIN users u ON u.id = c.sentBy
) sub
ORDER BY userId, created DESC;
I separated into two UNIONed SELECTs, to make the most of two separate indexes on chats - one with leading sentTo, one with leading sentBy. Just updated a closely related answer yesterday:
Finding all rows with unique combination of two columns
About DISTINCT ON:
Select first row in each GROUP BY group?
Might be optimized in various ways, depending on undisclosed information.
i have a table like this
UserFriends
Id UserId RequestId Status
1 1 2 1
2 1 3 1
3 1 4 0
4 3 2 1
5 3 4 1
basically the structure is if status is 0 request not accepted else 1 accepted and they are friends
i am trying to do get user 2 friends how can i do ?
IMPORTANT EDIT:
i am trying to get user 3's friends. you know if user 1 added user 3 they are friends and user 3 added 2 and 4 they friends too (user 3 friends must return 1, 2 and 4 this is basic explanation)
If I read correctly, a friendship is characterized by either a user inviting another user or by that user being invited by other users, and in both cases the request was accepted. If so, then the following UNION query should give the expected results:
SELECT RequestId
FROM UserFriends
WHERE UserId = 3 AND Status = 1
UNION
SELECT UserId
FROM UserFriends
WHERE RequestId = 3 AND Status = 1
I use a UNION here because a given user could appear as a friend more than once if a pair of users invited each other, or if an invitation were sent more than once. I am assuming that you don't want to report the same user as a friend more than once.
Output:
Demo here:
Rextester
I've a user table in my application.
Id Name ParentId
1 User1 0
2 User2 1
3 User3 1
4 User4 2
5 User5 2
The users have a relationship like grandparent->parent->child. to fetch the users related to a grand parent I'm using the following query
select * from user where ParentId=1 or ParentId in(select id from user where ParentId=1)
also these user have multiple roles in my role table and for fetching the count of rules a user having, I'm using select count(*) from group where userId=1.
Id Role UserId
1 Role 1 1
2 Role 2 1
3 Role 3 2
4 Role 4 2
5 Role 5 3
I need to fetch these both data in a single query .I'm not good with SQL and I know my first query is not perfect . How can I achieve this.
Your query is just need to be joined with your roles table.
SELECT u.id, count(r.id) no_of_roles
FROM user u left join roles r
on u.id = r.userid
WHERE u.ParentId=1
OR u.ParentId IN
(SELECT id FROM t WHERE ParentId=1
)
group by u.id;