Mysql inner join and filter result - mysql

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

Related

MySQL inner join not returning all records

I have the following 5 tables
appointments
id
user_id
client_id
date
notes
1
4
8
2022-04-19
test
2
4
16
2022-04-19
test
3
4
29
2022-04-19
test
appointments_services
id
appointment_id
service_id
1
1
7
2
2
10
clients
id
first_name
last_name
8
john
doe
16
john
doe
29
john
doe
users
id
first_name
last_name
4
john
doe
services
id
name
color
7
visit
ff0000
10
charge
ff0000
And I have the following query:
SELECT a.id, a.user_id, a.client_id, a.date, a.notes,
aserv.id AS asid,
aserv.appointment_id AS asappid,
aserv.service_id AS asservid,
c.id AS cid,
c.first_name AS cfirstname,
c.last_name AS clastname,
u.id AS uid,
u.first_name AS ufirstname,
u.last_name AS ulastname,
s.id AS sid,
s.name AS sname,
s.color AS scolor
FROM appointments AS a
INNER JOIN appointments_services AS aserv
ON a.id = aserv.id
INNER JOIN clients AS c
ON a.client_id = c.id
INNER JOIN users AS u
ON a.user_id = u.id
INNER JOIN services AS s
ON aserv.service_id = s.id
with the above query one row (appointment_id 3) will not display because it doesnt have a record in appointments_services table.
How can I change my sql query to display all records even if they dont have a connection within all tables?

Select mutual followers excluding blocked contacts

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).

Setting a clause for cross join (sql)

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

how to use select query in a Group_concat sub query in mysql

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;

mysql group by and take specific record from right join table

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