Reputation: 3
its my first time asking here
so basically i have 3 tables one storing customer basic data, one storing user attributes based on questions and another storing user prefferences which stoes multiple options of the same attributes.
lets say...
TABLE users:
userid, username, useremail, userphone
TABLE attributes:
attributeid,attributeofuser, attributename(number), attribute value(number)
TABLE prefferences:
preffid, preffofuser, preffattributename(number), preffattributevalue(number)
the attributename and attributevalues are numbers of the id of the attributes and valuesstored in another table.
if preffattributevalue is 0 means it doesnt matter so any attribute is ok
so what i need is to find all users that match the prefferences of a specific user based on their attributes and do it by percentage too , so not only 100% matches also less.
i have acomplished that doing loops of querys which looks very heavy and looking for a better option. thanks in advance
Upvotes: 0
Views: 368
Reputation: 11712
As Marty McVry said, this is an interesting query. Here is my solution. Note that I took the liberty of renaming your tables a bit...
The schema:
CREATE TABLE user (id int, username varchar(200), info varchar(200));
CREATE TABLE attr (id int, user_id int, a_name varchar(200), a_value varchar(200));
CREATE TABLE pref (id int, user_id int, pa_name varchar(200), pa_value varchar(200));
The query:
SELECT looker.username AS looker_name,
CONCAT("likes ",match_candidate.username,"\'s") AS candidate_name,
GROUP_CONCAT(" ", CONCAT(attr.a_value," ", attr.a_name)) AS attributes,
COUNT(attr.a_name) AS match_count
FROM pref
INNER JOIN attr ON attr.a_name = pref.pa_name
INNER JOIN user AS match_candidate ON match_candidate.id = attr.user_id
INNER JOIN user AS looker ON looker.id = pref.user_id
WHERE (pref.pa_value IS NULL OR pref.pa_value = attr.a_value) AND
pref.user_id = 101 AND looker.id <> match_candidate.id
GROUP BY candidate_name
ORDER BY match_count DESC;
Explanation:
We take the pref table and join it with the attr table to get the matching attribute names. The attr table can be joined with the user table to get the name of the candidates. Finally we can make the connection to the "looker", i.e. the user that wants his/her preferences matched. This is done by the second join with the user table but this time of course on the pref.user_id.
Now we need to sort out the attribute values that don't match. We do this by enforcing that all result rows have either NULL as preference attribute value or that that attribute value equals the attribute value of the matching candidate (attribute names already match by the join condition). To get the matching candidates of a specific "looker" we must also include this in the WHERE
clause (pref.user_id = 101
). Here 101
is just the example of one user's id. Finally we must make sure that we don't match the looker with him/herself (in case own preferences match own attributes).
The SELECT
fields are just a bit of toying around with GROUP_CONCAT
and CONCAT
To combine the matching attributes we use GROUP BY
.
I made a sqlfiddle to play around with. So in my example I used strings as attribute names and values. NULL in pref value means no preference means all attribute values of candidates match.
Side note: You could use the same table for attr and pref and adding a field defining its type.
Update side note: I updated this answer now quite a bit. If you checked out earlier versions of the fiddle, please follow the link again, because it may have changed.
Upvotes: 1
Reputation: 2856
Interesting problem...
Below query is untested, so not sure if it'll work.
SELECT u.*,
sub.num_match
FROM users AS u
INNER JOIN ( SELECT a.attributeofuser AS uid,
COUNT(a.attributeid) AS num_match
FROM preferences AS p
LEFT JOIN attributes AS a
ON p.preffattributename = a.attributename
WHERE p.prefofuser = $user_id
AND p.prefofuser <> a.attributeofuser
GROUP BY a.attributeofuser ) sub
ON u.userid = sub.uid
ORDER BY sub.num_match DESC;
First, the subquery gets all userid's of users having at least 1 attribute in common with the requesting user's preferences. It will also return the number of attributes they have in common, so you can calculate the match percentage later on.
Using the data from the subquery, you can then fetch the user data from your users
-table.
Use another query to fetch the number of preferences the requesting user has put in and you can calculate the match percentage!
Upvotes: 0