MySQL Relational friends scheme? - php

I was wondering how you'd work a PHP and MySQL Friends system?
I was thinking like, in the users table there would be a colum titled friends which would hold data with other user IDs who they are friends with seperated by commas,
for example, 1,3,56,3 - then explode this and foreach the array?Would that work?

That is one way to do it.
You may want to consider creating a new row for each friend.
For example:
Friend ID: 1
Friend Name: Bob
Friend ID: 2
Friend Name: Ron
Friend ID: 3
Friend Name: Joe
If Bob was friends with both Ron and Joe there would be 2 records in the friends table
id user friend
1 1 2
2 1 3
Then if joe became friends with bob but not ron the table would end up being
id user friend
1 1 2
2 1 3
3 3 1
This gives you flexibility down the road to add in more complex queries.

Don't do it as comma-separated strings, have a user_friends table with each friend relationship as a record. A comma-separated string isn't going to be usefully indexable or queryable.

Important example:
Friend 1 is connected with Friend 2
You have to lookup the user_id AND the friend_id to find all the friends of Friend 1

Related

Facebook or LinkedIn like connection suggestion profile alert

I have a "users" table like this:
+-----+------------+---------+---------------+
| uid | first_name | surname | email |
+-----+------------+---------+---------------+
1 joe bloggs joe#test.com
2 bill bloggs bill#test.com
3 john bloggs john#test.com
4 karl bloggs karl#test.com
and a "connections" table like this:
+----+---------+----------+--------+
| id | user_id | user_id2 | status |
+----+---------+----------+--------+
1 1 3 1
2 3 1 1
3 4 3 1
4 3 4 1
5 2 3 1
6 3 2 1
Here id is auto auto_increment user id is saved in either user_id or user_id2. Status 1 means connection is approved and active.
Now I want to send an email alert to users with profile suggestion like Facebook or LinkedIn do. I assume it is possible to get mutual connections between users but not sure how to do. I have tried but it is not perfect. I want to get these all with one mysql query with user and their suggested connection profile. Any idea how to do this?
Many thanks in advance!
Such algorithms are never perfect: you can never know exactly if two people know each other. People might live in the same building, go to the same work, have 100 friends in common and even share the same hobbies without knowing each other (of course the odds are not that great).
What Social networks do exactly is of course unknown (that's part of the way they make money). But some aspects are known. For instance the number of mutual friends are important (together with for instance location, interests, hobbies, education, work, surname,...).
Based on what you provide, one can more or less only use the number of mutual friends. This can be done using the following query:
SELECT a.user_id, b.user_id2, count(*) --Select the two ids and count the number of transitive relations
FROM connections as a, connections as b --Use the table twice (transitivity)
WHERE a.user_id2 = b.user_id -- Transitivity constraint
AND a.user_id < b.user_id2 -- Maintain strict ordening (can be dropped when checked)
AND a.status = 1 -- First relation must be confirmed.
AND b.status = 1 -- Second connection must be confirmed.
AND NOT EXISTS ( -- Not yet friends
SELECT *
FROM connections as c
WHERE c.user_id = a.user_id
AND c.user_id2 = b.user_id2
)
GROUP BY a.user_id, b.user_id2 -- Make sure we count them correctly.
As you can see here, the fiddle calculates that (1,2), (1,4) and (2,4) are not yet friends, and all have one mutual friend.
Once the number of mutual friends surpasses a certain threshold, one can propose friendship.
I would however advice you to make your table more compact: add a CHECK to the table such that user_id is always strictly less than user_id2 (CHECK(user_id < user_id2)). This makes the database more compact, for most implementations of a database tool faster as well and queries will become simpler. What is after all the difference between (1,3,1) and (3,1,1).

Php mysql routine for calculating in one table and place results in another table

I need a php routine for my mysql database. I have made an example to illustrate the problem:
Lets say I have a table that registrates customers and how much money they spend. A customer can have more registrations:
Table1:
Name - Amount
Jane - 3
Mark - 4
Sara - 5
Jane - 5
Jane - 6
Sara - 2
I want a routine that goes trough Table1, and finds how much each person has spend. I want the result in Table2, like this:
Table2:
Jane - 14
Mark - 4
Sara - 7
Do you have a solution to this?
insert into table2 select name, sum(amount) from table1 group by name;
SELECT Name, SUM(Amount) FROM Table1 GROUP BY Name

MySQL query problematic

I'm using PHP/MySQL and I have to create a new table from an existing one. Here's the problematic:
Table1:
photo_id email name_to creation_date link
1 foo1#bar.com paul 2012-11-21 link1.com
2 foo2#bar.com mark 2012-11-22 link2.com
3 foo1#bar.com alex 2012-11-23 link3.com
4 foo1#bar.com saul 2012-11-25 link4.com
5 foo1#bar.com john 2012-11-26 link5.com
6 foo2#bar.com math 2012-11-27 link6.com
7 foo3#bar.com fred 2012-11-28 link7.com
In Table1 the email is not unique, it can be repeated several times. Each link is different. With this data, I have to create a new table in which the email is unique with maximum of 3 links if there's more entries of one email (if so I need the data of the 3 latest entries).
So, in this case, Table2 would be like:
email link1 creation_date1 name_to1 link2 creation_date2 name_to2 link3 creation_date3 name_to3
foo1#bar.com link5.com 2012-11-26 john link4.com 2012-11-25 saul link3.com 2012-11-23 alex
foo2#bar.com link6.com 2012-11-27 math link2.com 2012-11-22 mark
foo3#bar.com link7.com 2012-11-28 fred
I know the GROUP_CONCAT feature but it's not really what I need here since the links would all be in the same column. Is it better to make a SELECT * FROM table1 and process the result into PHP arrays and after that create Table2 or a unique MySQL query would do the trick? Or create multiple MySQL tables?
Table1 is over 10 millions rows.
Any advice would be appreciate.
Thanks.
1) select all unique emails.
2) For each email, take the first 3 rows with that email ordered by creation_date descending.
3) Use that data to insert into new table.
Whatchu think?

Sql Distinct Count of Duplicates

I am doing a query on a mysql database. I have a main table where users are stored and another table where friends of that user are stored. For each user I want to see how many
friends they have. This is what I'm getting.
ID FirstName LastName FriendID
1 Andrew Smith 1
1 Andrew Smith 5
1 Andrew Smith 9
2 John Doe 3
2 John Doe 5
This is what I want to get.
ID FirstName LastName Friends
1 Andrew Smith 3
2 John Doe 2
If this is not enough detail to go on let me know and I will also show the tables and query I used.
SELECT ID, FirstName, LastName, COUNT(FriendID) AS Friends
FROM Users GROUP BY ID, FirstName, LastName
One hopes you're not really storing FirstName and LastName in every UserFriendLink record. If you are, it's time to normalize your database with a Users table (with ID, First, and Last) and a UserFriendsLink table (with UserID and FriendID).

How can I write a MySQL query for this database design?

Task 1
First I have a specific user, I want to see with which user it is connected to. Let's say alex in following table. I want to check if alex is connected to another user? In following table it is connected with John and christina, so I select john and christina.
Task 2
Now I have another user. Let's say martin, I want to see which of the previous selected users (john and christina) are connected with the martin.
ID user1 user2 status
1 alex john 1
2 john martin 1
3 Jane smith 1
4 smith john 1
5 christina alex 1
For example, in above table:
People who are connected to alex are john and christina. We want to check which of the users (john and christina) are connected with martin, and the result should be row2.
Update
You all are mentioning that the database design is not good, can you please tell me what is wrong with it? Here is my user table:
Table 1, users
ID username
and here is Table 2, user_connections
ConnectionID user1_ID user_Connectedto
I'm not sure your exact requirements but it would seem the database design you chose isn't really the best.
I think you would have wanted to go with a table with unique users. And then another table that links IDs of those users
--Users Table
ID Name
1 Alex
2 John
3 Jane
...
--UserConnection Table
ID ID_ConnectedTo
1 2
1 3
In this case, Alex is connected to John and Alex is connected to Jane.
Here's what you asked for, for you current schema:
SELECT user2 FROM
(SELECT user1, user2 FROM connections
UNION
SELECT user2, user1 FROM connections) t
WHERE user1 = 'martin'
You should consider the idea that "john connected with alex" isn't the same as "alex connected with john". If this is something like facebook, where a person has to allow a connection, then you'll want to build the connections both ways. If the connection is only in one direction, it means that the connection hasn't been approved by the other party yet.
Please review more normalized database designs suggested by other users.
firstly it would indeed be better to structure as SAGExSDX suggests...
to find any relationship:
SELECT * from connections where user1 = X OR user2 = X
Replace X with the username you need - or better the userID if you do refactor AS SAGExSDX suggests
I agree that the code isn't the best, but if you want a query which will grab double links, you'll have to be careful about the direction as mentioned by Marcus. It takes four distinct queries (joined with a union) using the table structure you describe:
SELECT user2 FROM connections
WHERE user1 IN (
SELECT user2 FROM connections
WHERE user1 = 'alex'
)
UNION
SELECT user1 FROM connections
WHERE user2 IN (
SELECT user1 FROM connections
WHERE user2 = 'alex'
)
UNION
SELECT user1 FROM connections
WHERE user2 IN (
SELECT user2 FROM connections
WHERE user1 = 'alex'
)
AND user1 <> 'alex'
UNION
SELECT user2 FROM connections
WHERE user1 IN (
SELECT user1 FROM connections
WHERE user2 = 'alex'
)
AND user2 <> 'alex'

Categories