Determine friends / friend requested / not friends using MySQL query - mysql

I have this MySQL table:
Let's imagine I am logged in as user 1 and I'm browsing the profile of user 2. As we are mutual friends (1 is friend with 2 and 2 is friend with 1), I need to echo "friends."
When I browse the profile of user 4, whose friendship I have requested, but they haven't accepted yet, I need to echo "friend requested."
When browsing any other user, I need to echo "add friend."
I can do the PHP part, I just don't know how to do the MySQL query.

SELECT COUNT(*) as `count`, `user`
FROM `friends`
WHERE
(`user` = 1 AND `friend` = 16) OR
(`user` = 16 AND `friend` = 1)
When count is
2 = mutual (you are friend with that person)
1 and user is you - you requested that person friendship
1 and user is that person - you are being requested for friendship by that person
0 = no connection between you and that person

select (case
when subquery.a > 0 and subquery.b > 0 then 'friends'
when subquery.a > 0 then 'friend requested'
else 'add friend' end) as "friend_string"
from (
select
(select count(*) from relationships where user = '$my_user_id' and friend = '$opponent_user_id') as a,
(select count(*) from relationships where user = '$opponent_user_id' and friend = '$my_user_id') as b
) subquery
Please replace relationships with your table name, and $ variables with yours.

Are you expecting something like this? (just for the sql part, not the PHP :) )
SQLFIDDLE DEMO
SELECT DISTINCT a. user,
CASE
WHEN a.user = b.friend
AND a.friend = b.user THEN b.friend
ELSE ''
end friends,
CASE
WHEN a.user = b.friend
AND a.friend <> b.user THEN a.friend
ELSE ''
end friendreq,
CASE
WHEN a.user <> b.friend
AND a.friend <> b.user THEN a.friend
ELSE ''
end addfriend
FROM demo a
LEFT JOIN demo b
ON a.id > b.id;
| USER | FRIENDS | FRIENDREQ | ADDFRIEND |
------------------------------------------
| 1 | | | |
| 2 | 2 | | |
| 1 | | | 16 |
| 1 | | 16 | |
| 16 | | | |
| 16 | | | 1 |
| 16 | 16 | | |
| 1 | | | 4 |
| 1 | | 4 | |

Related

How to create right query?

I'm trying write a query:
SELECT id FROM users WHERE status = 3
But if this sample returns an empty response, then I need instead to select the id where status = 4, and if it returns empty again, where status = 5.
How can I write a single query to solve this?
I think you simply want:
SELECT id
FROM users
WHERE status >= 3
ORDER BY status asc
LIMIT 1;
If you want multiple users:
SELECT u.id
FROM users u
WHERE u.status = (SELECT MIN(u2.status)
FROM users u2
WHERE u2.status >= 3
);
If you have a fixed list you want to test, you can also use:
select u.id
from users u
where u.status = 3
union all
select u.id
from users u
where u.status = 4 and
not exists (select 1 from users u2 where u2.status in (3))
union all
select u.id
from users u
where u.status = 5 and
not exists (select 1 from users u2 where u2.status in (3, 4));
You can use OR condition or use IN operator
SELECT id FROM users WHERE status = 3 or status = 3 or status = 5
or
SELECT id FROM users WHERE status IN (3,4,5)
I will use the case statement in the where clause:
select id
from users
where status = case when status = 3 and id is null then 4
when status = 4 and id is null then 5
else 3
end
Let me know if you have any question.
Assuming that your table look like this:
+----+--------+
| id | status |
+----+--------+
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 3 | 3 |
| 3 | 4 |
| 4 | 4 |
| 4 | 5 |
| 5 | 5 |
+----+--------+
And based on your condition where you want to see the lowest status first for each id, you can use MIN() operator.
So, from your original query:
SELECT id,MIN(status) FROM users GROUP BY id;
Then you'll get a result like this:
+----+-------------+
| id | MIN(status) |
+----+-------------+
| 1 | 3 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
+----+-------------+

Finding many matches to one row in the same table in mysql

My table is this.
users_table:
id | name | admin | property_id
-----------------------------------
1 | x | 1 | 0
2 | y | 1 | 0
3 | z | 0 | 1
4 | t | 0 | 2
4 | u | 0 | 2
4 | o | 0 | 2
I have two records which are admin and some other records which belong to one of these two records by matching the property_id with the id.
In the end what I want is the admin row data and the count of its properties.
The problem is that the data is all in the same table.
This is what should be the output from the desired query.
id | name | admin | property_count
-----------------------------------
1 | x | 1 | 1
2 | y | 1 | 3
http://sqlfiddle.com/#!9/5ad1fb/4
SELECT u.*, COUNT(ut.id) property_count
FROM users_table u
LEFT JOIN users_table ut
ON u.id = ut.property_id
WHERE u.admin = 1
GROUP BY u.id, u.name, u.admin
You seem to want a self-join and aggregation:
select t1a.id, t1a.name, t1a.admin, count(t1.id) as property_count
from table1 t1a left join
table1 t1
on t1a.id = t1.property_id
where t1a.admin = 1
group by t1a.id, t1a.name, t1a.admin;
There is, incidentally, a trickier way to do this without a join:
select (case when admin = 1 then id else property_id end) as id,
max(case when admin = 1 then name end) as name,
max(admin) as admin,
sum( admin <> 1 ) as property_count
from table1 t1
group by (case when admin = 1 then id else property_id end);

How do I join multiple entries in one table into a single relationship status in MySQL?

I have a table Follow, which only holds records of which UserID follows which TargetID.
If asked for user A:
If neither A or B are following eachother, they have status of 0 for unrelated, and aren't included in the results.
If user A is following B but not vice versa, B has status 1 for
being followed.
If user B is following A but not vice versa, B has
status 2 for being a follower.
If A is following B, and B following
A, B has status of 3 for being a friend.
How can I, in a single MySQL query, get the relationship status for a given user and all its relationships above status 0?
Example:
Users:
+----+-------+
| id | Name |
+----+-------+
| 1 | Bob |
| 2 | Steve |
| 3 | Scott |
| 4 | Mary |
+----+-------+
Follow:
+----+--------+----------+
| id | UserID | TargetID |
+----+--------+----------+
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
| 4 | 4 | 1 |
+----+--------+----------+
Expected result for user 1:
+----------+--------+-------+
| TargetID | Status | Name |
+----------+--------+-------+
| 2 | 3 | Steve | (friend)
| 3 | 1 | Scott | (following)
| 4 | 2 | Mary | (follower)
+----------+--------+-------+
You can use subqueries as illustrated below:
-- FOR USER 1
SELECT A.id TargetID,
SUM(IFNULL((SELECT 1 C FROM Follow B WHERE B.UserID=1 AND B.TargetID=A.id),0) +
IFNULL((SELECT 2 C FROM Follow D WHERE A.id=D.UserID AND D.TargetID=1), 0)) Status
, A.name
FROM (SELECT * FROM Users WHERE ID<>1) A
GROUP BY A.id, A.Name
HAVING Status>0; -- for a compact result
-- NOW GLOBALLY
SELECT A.UserID, A.id TargetID,
SUM(IFNULL((SELECT 1 C FROM Follow B WHERE B.UserID=A.UserID AND B.TargetID=A.id),0) +
IFNULL((SELECT 2 C FROM Follow D WHERE A.id=D.UserID AND D.TargetID=A.UserID), 0)) Status
, A.name
FROM (SELECT E.id UserID, F.* FROM Users E JOIN Users F ON E.id<>F.id) A
GROUP BY A.UserID, A.id, A.Name
HAVING Status>0 -- for a compact result
ORDER BY A.UserID;
See DEMO on SQL Fiddle
I have not tried this but try something among the lines of:
Select t.targetid as TargetId,
IF (
(select count(id) from follow where
follow.Userid = f.target.id and follow.target_id = u.id) > 1,
-- mean’s the target is following user 1
(IF (
(select count(id) from follow where
follow.Userid = u.id and follow.target_id = f.targetid) > 1, 3, 2))
-- if user1 is following aswell, then its a friend, else its a follower
, 1)
-- else means its a following
as status,
u.name as Name from follow f
inner Join users u on u.id = f.targetid
where u.id = 1
Inner join to select user 1's relations (if it doesn't exist, they aren't related)
If there is a record, means they are one of 3:

LEFT JOIN and WHERE with NULL values in the result

A simple query gives me user1's relationship with other users:
select u.id, u.name, ur.*
from users u
left join user_relationships ur
on ((ur.source_user_id = 1 and target_user_id = u.id) OR
(ur.source_user_id = u.id and target_user_id = 1))
where u.id != 1
ORDER BY u.id;
+----+-------+----------+--------+------+
| id | name | rel_from | rel_to | type |
+----+-------+----------+--------+------+
| 2 | beta | 2 | 1 | 2 |
| 3 | gamma | 1 | 3 | 2 |
| 4 | delta | 4 | 1 | 1 |
| 5 | five | NULL | NULL | NULL |
+----+-------+----------+--------+------+
But I only want a list of users with whom the relationship type is not 2 ('delta' and 'five').
I tried some approaches.
-- Approach 1
-- -----------------------------
where
(u.id != 1) AND
(ur.type != 2)
-- gives 'delta', not 'five'
-- Approach 2
-- -----------------------------
left join user_relationships ur
on ((ur.source_user_id = 1 and target_user_id = u.id) OR
(ur.source_user_id = u.id and target_user_id = 1)) AND
(ur.type != 2)
where
(u.id != 1)
ORDER BY u.id;
-- ur.* fields are NULL
-- (all rows, except for 'delta')
-- Approach 3
-- -----------------------------
where
(u.id != 1) AND
((ur.type != 2) OR
(ur.type IS NULL))
-- this works, but why ?
(A) Why Approaches 1,2 don't work, but 3 does ?
(B) Is there another (perhaps more elegant) way to achieve the same result ?
Kaya,
When you work with possible null values should use the IS NULL comparative.
So your where could be:
where
(u.id != 1) AND
(ur.type != 2 OR ur.type IS NULL)

How do I run this MySQL JOIN query?

Let's say I have 2 tables.
The first table is a list of personas. A user can have many personas.
mysql> select id, user_id, name from personas_personas;
+----+---------+--------------+
| id | user_id | name |
+----+---------+--------------+
| 8 | 1 | startup |
| 9 | 1 | nerd |
| 10 | 1 | close |
| 12 | 2 | Nerd |
| 13 | 2 | Startup |
| 14 | 2 | Photographer |
+----+---------+--------------+
6 rows in set (0.00 sec)
Now, I have another table called "approvals".
mysql> select id, from_user_id, to_user_id, persona_id from friends_approvals;
+----+--------------+------------+------------+
| id | from_user_id | to_user_id | persona_id |
+----+--------------+------------+------------+
| 2 | 1 | 2 | 8 |
| 3 | 1 | 2 | 9 |
+----+--------------+------------+------------+
2 rows in set (0.00 sec)
If from_user wants to approve to_user to a persona, then a record is inserted.
I'm trying to do this query...
Given a user, find all its personas. Then, for each persona, determine if it's approved for a certain to_user. If so, return is_approved=1 in the result set. Otherwise, return is_approved=0 in the result set.
So this is where I start:
SELECT *
FROM personas_personas
WHERE user_id = 1
LEFT JOIN friends_approvals ON
...but i don't know where to go from here.
So, the final result set should have all the columns in the personas_personas table, and then also is_approved for each of the results.
SELECT
pp.*,
CASE
WHEN exists (
SELECT
*
FROM
friends_approvals fa
WHERE
fa.from_user_id = pp.user_id AND
fa.persona_id = pp.id AND
fa.to_user_id = 2
)
THEN 1
ELSE 0
END as is_approved
FROM
personas_personas pp
WHERE
pp.user_id=1
Or, depending on your taste:
SELECT
pp.*,
CASE
WHEN fa.from_user_id IS NOT NULL
THEN 1
ELSE 0
END as is_approved
FROM
personas_personas pp
LEFT OUTER JOIN friends_approvals fa ON
pp.user_id = fa.from_user_id AND
pp.id = fa.persona_id AND
fa.to_user_id = 2
WHERE
pp.user_id=1
If I'm understanding your needs correctly, you can do this:
SELECT personas_personas.*,
CASE WHEN friends_approvals IS NULL THEN 0 ELSE 1 END AS is_approved
FROM personas_personas
LEFT
OUTER
JOIN friends_approvals
ON friends_approvals.from_user_id = ...
AND friends_approvals.to_user_id = personas_personas.user_id
AND friends_approvals.persona_id = personas_personas.id
WHERE personas_personas.user_id = ...
;
That will find every personas_personas record with the specified user_id, together with an indicator of whether that user, in that persona, has been "approved" by a specified from_user_id.
(If that's not what you want, then please clarify!)