Users Table
id activated
--- ------------
1 1
2 1
3 0
4 1
5 1
6 1
Follow table
follower_id following_id
------------ --------------
1 2
2 1
4 2
5 1
3 2
5 2
6 1
3 4
6 2
3 1
4 1
Blocking table
blocking_id blocked_id
------------ --------------
2 4
Let's say I am the user with the id of 2
Expected Result
user_id mutual_followers
------------- -----------------
1 2
5 0
6 0
I want to get the mutual followers of users and exclude blocking or blocked and users whose activated is 0.
How can I get it done all the way by MySQL?
First use a CTE that returns all the followers of the user, filtered by your conditions to be active and non-blocked and then for each of the followers get their non-blocked followers.
Then filter the followers of the followers so that only the mutual followers are left (or none) and aggregate:
WITH cte AS (
SELECT f.follower_id user_id
FROM Follow f
INNER JOIN Users u ON u.id = f.follower_id AND u.activated
LEFT JOIN Blocking b ON b.blocking_id = f.following_id AND b.blocked_id = f.follower_id
WHERE f.following_id = 2 AND b.blocked_id IS NULL
)
SELECT c1.user_id,
COUNT(c2.user_id) mutual_followers
FROM cte c1
LEFT JOIN Follow f ON f.following_id = c1.user_id
LEFT JOIN Blocking b ON b.blocking_id = f.following_id AND b.blocked_id = f.follower_id
LEFT JOIN cte c2 ON c2.user_id = f.follower_id
WHERE b.blocked_id IS NULL
GROUP BY c1.user_id;
See the demo1 or demo2 (in case the 1st is inaccessible or sometimes does not run).
Related
I have three tables in a database, as follows:
users:
user_id name pbal
1 m1 100
2 m2 200
3 m3 300
4 m4 400
5 m5 500
payouts:
id user_id amount
1 1 100
2 1 200
3 2 300
4 1 400
blocked:
id user_id status
------ -------- ------
1 2 block
2 3 block
Now I want to make a list that excludes users whose user_id is in the blocked table, and that calculates a new total amount based on the pbal from users and the amount from the related rows in payouts:
name total_amount
----- ------------
m1 800
m5 500
m4 400
I have been trying for half an hour, but failed. Can someone help me?
Here's an example:
SELECT u.name, u.user_id, MAX(u.pbal) + SUM(p.amount) AS total_amount
FROM dbo.Payouts p
INNER JOIN dbo.Users u ON u.user_id = p.user_id
LEFT OUTER JOIN dbo.Blocked b ON u.user_id = b.user_id
WHERE b.user_id IS NULL
GROUP BY u.user_id, u.name
ORDER BY MAX(u.pbal) + SUM(p.amount) DESC;
Here is a possible answer:
SELECT u.name, u.user_id,
u.pbal + (
-- this takes amounts from the payouts table
SELECT SUM(p.amount)
FROM dbo.Payouts p
WHERE u.user_id = p.user_id
) AS total
FROM dbo.Users u
WHERE NOT EXISTS (
-- this excludes blocked users
SELECT *
FROM dbo.Blocked b
WHERE u.user_id = b.user_id
)
ORDER BY total;
I prefer subqueries in this case because they make it a bit more explicit
I am looking to show a mutual friends function but my user friends list is stored on another table.
I want to know if it's possible to use the data of each row as a clause for join B
SELECT * FROM ( SELECT * FROM `users`) a
CROSS JOIN (SELECT COUNT(*) AS MUTUAL_FRIENDS
FROM `user_friends` WHERE `friend_to` = `a`.`userid`) b
ORDER BY `b`.`MUTUAL_FRIENDS` ASC
What I am looking to do is use the userid from users table as a clause for the join with:
`friend_to` = `a`.`userid`
Expected results:
+--------=+---------+-----------+--------------+
| userid | Username |Photo_URL |MUTUAL_FRIENDS|
+---------+---------+-----------+--------------+
1 Somename1 /image1.png 3
4 Somename4 /image4.png 2
2 Somename2 /image2.png 1
3 Somename3 /image3.png 0
5 Somename5 /image5.png 0
Friends table:
+--------=+---------+-----------+
| friend_id | userid |friend_to |
+---------+---------+-----------+
1 1 2
2 2 1
3 1 3
4 3 1
5 1 4
6 4 1
Users Table
+--------=+---------+-----------+
| userid | Username |Photo_URL |
+---------+---------+-----------+
1 Somename1 /image1.png
2 Somename2 /image2.png
3 Somename3 /image3.png
4 Somename4 /image4.png
5 Somename5 /image5.png
Or am I doing this totaly wrong?
Here is one approach.
With CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a
CROSS JOIN Friends b
WHERE a.userid = b.friend_to and a.friend_to = b.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
Without CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a, Friends b
WHERE a.friend_to = b.userid and b.friend_to = a.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
I will try to explain little by little and please correct me if there is error.
The condition a.friend_to = b.userid and b.friend_to = a.userid is
used to select only mutual friend. Then if a user has this kind of
"mutual connection," the corresponding userid will appear once.
Get the count along with the userid.
Left join the userid and count table.
Result
userid Username Photo_URL MUTUAL_FRIENDS
1 Somename1 /image1.png 3
2 Somename2 /image2.png 1
3 Somename3 /image3.png 1
4 Somename4 /image4.png 1
5 Somename5 /image5.png 0
Given the data, user1 is mutual friend of user2, user3 and user4. User2 is only mutual friend of user 1 and so as user 3 and user4.
With CROSS JOIN SQL Fiddle
Without CROSS JOIN SQL Fiddle
I have 3 tables:
tbl_user stores all user details (user_id,name,address)
user_id name address
1 a (shop) home
2 b (shop) bakerstreet
3 c (staff) wallstreet
4 d (staff) georgia
5 e (staff) sydney
tbl_user_group stores user type (user_id,user_type : 1=shop_owner,2=staff)
user_id user_type
1 1
2 1
3 2
4 2
5 2
tbl_user_association holds the shop_owner and staff relation (shop_owner_id, staff_id)
shop_owner_id staff_id
1 3
1 4
1 5
2 3
2 4
desired result
i want to display the list of staffs and the respective shops that they are associated with as follows:
user_id staff_name shop_owner
3 c a,b
4 d a,b
5 e a
I tried using the group_concat as mentioned here. The query is as follows:
SELECT
u.id AS user_id,
u.name AS staff_name,
(SELECT GROUP_CONCAT(u.name separator ',') FROM tbl_user u WHERE u.id = ua.shop_owner_id) AS
shop_owner
FROM tbl_user u
JOIN tbl_user_group ug ON u.id = ug.user_id
LEFT JOIN tbl_user_association ua ON u.id = ua.staff_id
WHERE ug.user_type = 2
GROUP BY u.id
But it returns single row of staffs as below. where have i gone wrong?
user_id staff_name shop_owner
3 c a
4 d a
5 e a
This is how I'd do it:
SELECT
u.user_id,
u.name,
GROUP_CONCAT( so.name )
FROM
tbl_user_group ug
INNER JOIN tbl_user u
ON ( ug.user_id = u.user_id )
INNER JOIN tbl_user_association ua
ON ( ua.staff_id = u.user_id )
INNER JOIN tbl_user so -- here join again the user table to get shop owners names
ON ( ua.shop_owner_id = so.user_id )
WHERE
ug.user_type = 2
GROUP BY
u.user_id;
I have database with following data structure with sample data. Each company have multiple members. The relationship is in the company_member table. Please note only required fields I have given below.
company
id title
1 company-1
2 company-2
company_member
companyid memberid
1 1
1 2
1 3
2 4
2 5
2 6
member
id firstname member_type_id
1 Name-1 2
2 Name-2 3
3 Name-3 3
4 Name-4 3
5 Name-5 2
6 Name-6 1
member_type
id user_level
1 0
2 1
3 2
I want list of unique companies with one member from each. But the member should be the lowest user_level within the company. i.e, following result should come;
result
companyid company_title memberid member_name user_level
1 company-1 1 Name-1 1
2 company-2 6 Name-6 0
I want to know how to get one member with lowest user level among the same company.
This is a bit complicated one, however this is one way of doing it using not exists, for bigger tables its wise to use not exits since using pivot tables it will not use index.
select
c.id,
c.title,
m.id as member_id,
m.firstname,
mt.user_level
from company_member_map cmp
join company c on c.id = cmp.companyid
join member m on m.id = cmp.memberid
join member_type mt on mt.id = m.member_type_id
where not exists
(
select 1 from company_member_map t1
join member t2 on t2.id = t1.memberid
join member_type t3 on t3.id = t2.member_type_id
where
t1.companyid = cmp.companyid
and t3.user_level < mt.user_level
)
DEMO
Finally I found solution:
select c.id companyid, c.title company_title, m.firstname member_name, mt.user_level
from company c
inner join company_member cm on cm.companyid = c.id
inner join member m on m.id = cm.memberid
inner join member_type mt on mt.id = m.member_type_id
inner join
(select c1.id companyid, mt1.user_level
from company c1
join company_member cm1 on cm1.companyid = c1.id
join member m1 on m1.id = cm1.memberid
join member_type mt1 on mt1.id = m1.member_type_id
group by c1.id,m1.id
order by user_level asc
) sq on c.id = sq.companyid and sq.user_level = mt.user_level
group by c.id;
Correct this, if anyone have better solution or simplified solution.
Check this SQL Fiddle
Table 1: users
id name
1 name 1
2 name 2
Table 2: user_city
user_id city_id
1 1
1 2
2 1
2 2
Table 3: city
id name_city
1 HCM
2 Ha Noi
3 DA NAng
Sql of me:
select a.*,c.name_city
FROM users as a
INNER JOIN
user_city as b
ON b.user_id = a.id
INNER JOIN city as c
ON c.id = b.city_id
Results:
id name name_city
1 name 1 HCM
2 name 2 Ha Noi
1 name 1 Ha Noi
2 name 2 HCM
I want result is:
Results:
id name name_city
1 name 1 HCM,Ha Noi
2 name 2 HCM,Ha Noi
you can use GROUP_CONCAT AND GROUP BY to get the result
SELECT U.id, U.name, GROUP_CONCAT(c.name_city)
FROM users u
join user_city uc
on u.id = uc.user_id
join city c
on uc.city_id = c.id
group by u.id, u.name