show top 5 users on logged user dashboard based on preferences - php

I want to show top 5 users on logged user dashboard based on following criteria:
users are opting following attributes in their profile:
Relationship preferences,
Hobbies,
Interests,
Language etc
More the preferences will match, highest priority to user's profile will be assigned
table_users
userid ufname ulname gender
--------------------------------
1 test1 Test2 M
2 testF TestF F
3 testF1 TestF1 F
4 testF2 TestF2 F
5 testF5 TestF2 F
table_preferences
preference_id user_preferences
--------------------------------
1 Cooking
2 Gardening
3 Smoking
4 Single
5 widow
6 traveling
table_user_preferences
userid user_preference_id
--------------------------------
1 1
1 2
1 3
1 4
2 3
2 4
3 2
3 3
3 6
4 1
5 1
5 2
5 3
5 4
5 6
Now, suppose user one is logged in, on his dashboard other registered users (with opposite i.e. gender female) will get display whose highest attributes are matching. As we can see, user five 5 matches most of the attributes so it will be display on top of list and rest will be get display accordingly as follows:
Result required:
User_id ufname
5 testF5
3 testF1
2 testF
4 testF2
My Query is I am thinking to use relevance search. Will it be suitable. Anyone can help me any suggestions.

Simple use MYSQL JOIN and SUBQUERY
1) Use subquery to get the preference of logged in user.
2) Then join table_user_preferences with table_users with ON tu.userid = tup.userid and AND tu.gender !=$current_user_gender and IN( ) condition to match the prefrence with logged in user preference.
3) Finally group the user and apply order by count of match preference
select tu.*,tup.userid,count(1) as total_match
from table_user_preferences as tup
join table_users as tu
ON tu.userid =tup.userid
where tup.user_preference_id
IN (select up.user_preference_id from table_user_preferences as up where up.userid=$current_userid)
AND tu.gender !=$current_user_gender
group by tup.userid order by total_match desc limit 5

Related

Joining two mysql tables to get a true/false column

I'm working with PHP and MySql. I'm trying to find a way to select a number of movies from a mysql table, but apart from the movies table I have a watchlist table that stores a userID and the movieID of the movies he/she has added to his/her watchlist:
id userID movieID
=====================================
1 1 3
2 1 5
3 1 7
4 2 3
5 2 2
6 3 2
The movies table looks something like this
movieID title duration
=============================
1 tit1 34:43
2 tit2 35:43
3 tit3 24:43
4 tit4 34:13
5 tit5 11:43
6 tit6 22:43
7 tit7 33:43
The result I'm after is (for example for the user with ID 1):
movieID title duration added
=======================================
1 tit1 34:43 false
2 tit2 35:43 false
3 tit3 24:43 true
4 tit4 34:13 false
5 tit5 11:43 true
6 tit6 22:43 false
7 tit7 33:43 true
Is there a way to join both the movies and the watchlist table to produce the desired result?
Thanks.
You can get the required output by using a LEFT JOIN and then checking for a NULL in the join table.
SELECT m.*, IF(w.id IS NULL, 0, 1) AS added
FROM movies m
LEFT JOIN watchlist w ON (m.movieID = w.movieID AND w.userID = 1)
GROUP BY m.movieID

Optimal way to store follower and following MySQL

I have 2 tables one is user and another is company. Both have the following columns common while other columns are different.
id email name
1 first#email.com First user
2 second#email.com Second User
3 third#email.com Third User
Now a user can follow many companies but a company does not follow back user. Company should have data with users who follow them and a user should also store the companies they are following.
What is the simplest and optimal to make this happen on MySQL? Either should I create separate table for it or just add a column on existing tables with array of followers. Please answer assuming I have working level of knowledge on PHP and MySQL.
You have the tables User and Company. Let's suppose they contain these values:
User
UserId
UserName
UserMail
1
Alice
alice#mail.com
2
Bob
bob#mail.com
Company
CompanyId
CompanyName
CompanyAddress
1
Microsoft
Redmond
2
Apple
Cupertino
3
Google
Mountain View
Then you should create a many-to-many table - e.g. let's call it UserCompany - which contains at least the columns UserId and CompanyId (coming from the first two tables).
Let's suppose that Alice follows Microsoft and Apple, and Bob follows Google. Your new UserCompany table will contain the following data:
UserId
CompanyId
1
1
1
2
2
3
Company should have data of users who follow them
Here you are the query to get the data of the users that follow Microsoft:
SELECT u.UserName, u.UserMail
FROM User AS u
JOIN UserCompany AS uc ON u.UserId = uc.UserId
WHERE uc.CompanyId = 1
User should also have data of companies they are following.
And here you are the query to get the data of the companies followed by Alice:
SELECT c.CompanyName, c.CompanyCity
FROM UserCompany AS uc
JOIN Company AS c ON c.CompanyId = uc.CompanyId
WHERE uc.UserId = 1
The simplest solution is to have a MANY-TO-MANY join table to link these 2 tables. You can do this with either 2 MANY-TO-MANY tables or a single one.
For example 2 table:
user_follows_company
ID CompanyID UserID
---- ------ ---------
1 1 5
1 1 6
1 1 8
1 2 5
You can get the companies a user follows by using the following SQL:
SELECT * FROM company c JOIN user_follows_company ufc on ufc.companyID = c.ID WHERE user = $USER_ID
company_follows_user
ID CompanyID UserID
---- --------- ---------
1 3 5
1 3 6
1 5 3
1 5 4
You can get the users a company follows by using the following SQL:
SELECT * FROM user u JOIN company_follow_user cfu on cfu.userID = u.ID WHERE user = $USER_ID
or you can do this with a single table and have a column that designates which direction is being followed:
follows_table
ID CompanyID UserID Initiator
---- --------- --------- ---------
1 3 5 Company
1 3 6 Company
1 5 3 Company
1 5 4 Company
1 5 1 User
1 6 1 User
1 8 1 User
1 5 2 User
Note that storing the "initiator" as a string is not a good idea - it probably should be an int or an ENUM
To query on this table, do the following queries:
Companies a user follows:
SELECT * FROM company c JOIN follows_table ft on ft.userID = c.ID WHERE user = $USER_ID AND ft.initiator = 'user'
Users a company follows:
SELECT * FROM user u JOIN follows_table ft on ft.userID = u.ID WHERE companyID = $$COMPANY_ID AND ft.initiator = 'company'

" People Who Liked this Also Liked " Query in Mysql PHP

Music table
id | title
1 Rap God
2 Blank Space
3 Bad Blood
4 Speedom
5 Hit 'em up
Like table
u_id | m_id
1 1
1 2
1 4
1 5
2 3
2 4
2 5
3 1
3 5
4 1
4 2
4 5
Now if someone visits music with m_id = 1
Then the output might be like
m_id
5
2
4
To explain this a bit...
As m_id = 1 is liked by users -> {1,3,4} which in turn likes ->{2,4,5} musics. Since m_id=5 is liked by max number of users its first followed by m_id = 2 and m_id = 4.
My Try
I queried the users who liked m_id = 1
SELECT u_id FROM likes WHERE m_id =1
Then i stored in in an array and selected each of their likes and
arranged them in desc order of count.
But it is a very slow and long process is there any way i can do this ?
p.s I have heard of Association Rules and Bayesian theorem can be user to achieve this. But can anyone help me out with an example ?
You can JOIN back on the Like table and do something like this.
SELECT also_like.m_id, COUNT(also_like.m_id)
FROM [like] AS did_like
JOIN [like] AS also_like ON
also_like.u_id = did_like.u_id
AND also_like.m_id != did_like.m_id
WHERE did_like.m_id = 1
GROUP BY also_like.m_id
ORDER BY COUNT(also_like.m_id)
Essentially you are getting a list of users who liked an item then getting a complete list of those user's likes excluding the item they just liked.
You can then add a HAVING clause or LIMIT to filter things down a bit more.
using a subquery ...
SELECT m_id, count(u_id) as Rank FROM `like`
WHERE u_id in
(
SELECT u_id
FROM `like`
WHERE m_id = 1
)
AND m_id <> 1
GROUP BY m_id
ORDER BY Rank DESC
and optionally
LIMIT 0, 10
or how many "alsolikes" you want to display

Joining tables for a comment list and determine if the user already upvoted/downvoted the comment

I've been building a comment system for a project of my own and the way I currently determine if the currently logged user has voted (up or down) on the comment is not very.. smart. Right now I query the database everytime a comment is going to be displayed, which is not ideal for even 100+ comments per page. That means 100+ extra queries.
I tried using JOIN and LEFT JOIN and LEFT OUTER JOIN and I can't figure out how to do this by myself. Nothing that I tried gives me the result I need.
This is what I came up with but I can't figure out how to only merge the values where the user has voted.
$q_get_comments = $conn->prepare('
SELECT comments.id,
comments.parent,
comments.subpage,
comments.author_id,
comments.author,
comments.message_cut,
comments.regdate,
comments.points,
votes_comments.user_id,
votes_comments.user_name,
votes_comments.comm_id,
votes_comments.direction
FROM comments LEFT JOIN votes_comments
ON comments.id = votes_comments.comm_id
WHERE comments.subpage= :subpage
ORDER BY points DESC, regdate DESC');
$q_get_comments->execute(array(':subpage' => $sub_id));
and my tables are set up like this:
Comments
id parent subpage author_id author message message_cut ip regdate points up down
------------------------------------------------------------------------------------------
1 0 68 6 name msg <p>msg</p> x date 5 4 0
2 0 68 6 name msg <p>msg</p> x date 3 2 0
3 2 68 6 name msg <p>msg</p> x date 2 3 2
Votes
id user_id user_name comm_id direction
------------------------------------------
1 6 Chris 2 0
2 6 Chris 3 2
3 6 Chris 1 1
votes.comm_id matches comments.id and that's the way I tried to join the tables.
But I only want to join the results where user_id = 6 and still show all the comments for the subpage, and only add.. say.. the user_id and direction to the according result in comments
The result I need with direction's value at the end to determine the vote status.
id parent subpage author_id author message message_cut ip regdate points up down direction
------------------------------------------------------------------------------------------
1 0 68 6 name msg <p>msg</p> x date 5 4 0 0
2 0 68 6 name msg <p>msg</p> x date 3 2 0 NULL
3 2 68 6 name msg <p>msg</p> x date 2 3 2 2
If direction is NULL, or blank field maybe, the user did not vote on this comment, if it has a value he did, or something along these lines.
( in the code direction 0 means a revoked/neutral vote, 1 means upvote and 2 means downvote, so if direction exists I can know that the user voted on this comment in some way, and I can show the right html for his vote )
Thank you in advance for any help or tips you can give!
Simply make 2 queries (sudo code, just showing sql, not the actual db calls) to select comments and votes, then merge the results in php:
$comments = $db->prepare('SELECT * FROM comments WHERE subpage = :subpage');
$comments->execute(array('subpage' => $subpage_id));
$commentsById=array();
foreach($comments as $comment)
$commentsById[$comment['id']]=$comment
$votes = $db->prepare('SELECT * FROM votes WHERE user_id = :user_id AND comm_id IN (' . implode(",", array_keys($commentsById)) . ')');
$votes->execute(array('user_id' => $user_id)); // the user_id of the user
foreach($votes as $vote)
$commentsById[$vote['comm_id']]['direction'] = $vote['direction'];
var_dump($commentsById);

How do I query mysql data with array

I have 2 tables colorcode & users
colorcode
ID colorid colorname
------------------------
1 1 yellow
2 2 black
3 3 red
4 4 white
users
ID userid colorid
------------------------
1 1 1,2
2 2 3,4
3 3 1,3,4
4 4 1
How do I retrieve & query individual colorid
$aa = $db->query("SELECT * FROM colorcode");
$colors = array();
while ($colordata = mysql_fetch_assoc($aa)) {
$colors[] = $colordata["colorid"];
}
Let's say I want query which users have yellow color & what it's the statement should I use for users
SELECT .. FROM users
WHERE colorid ....
It's a bad design... since you're trying to access the individual color_ids in the user table, but have stored them as a comma-separated list, you canot have the database do a normal join for you - you've killed off the main point of using a relational database by making it impossible to for the database to do the relating for you.
However, since you're on mysql, you're in luck - mysql has a function for cases like this:
SELECT users.ID, userid, GROUP_CONCAT(colorcode.colorname)
FROM users
LEFT JOIN colorcode ON FIND_IN_SET(colorcode.ID, users.colorid)
GROUP BY users.id
SELECT * FROM users
WHERE colorid LIKE "%1%"
But what I would really do is make a link table from users to colors:
usersToColors:
ID userid colorid
------------------------
1 1 1
2 1 2
3 2 3
4 2 4
...
Then you could do:
SELECT * FROM users u, usersToColors utc
WHERE u.userid = utc.userid
AND utc.colorid = 1;
Or even:
SELECT * FROM users u, usersToColors utc, colors c
WHERE u.userid = utc.userid
AND utc.colorid = c.colorid
AND c.colorname = "yellow";

Categories