Is it possible to get all the users that might be linked to UserID1?
For example:
UserID1 referred UserID2 and UserID5
UserID2 referred UserID3
UserID3 referred UserID4
Result on UserID1's page:
+UserID2
+UserID5
++UserID3
+++UserID4
How I am currently doing it:
$user_data['id']=1;
$primary_referral_query=mysqli_query($conn, "SELECT username FROM users WHERE referrer=$user_data[id]");
while($primary_referral=mysqli_fetch_array($primary_referral_query))
{
echo '+'.$primary_referral['username'].'<br>';
}
$secondary_referral_query=mysqli_query($conn, "SELECT a.username, b.username, c.username AS users_c_username FROM users AS a, users AS b, users AS c WHERE b.referrer = a.id AND a.id <> b.id AND c.referrer = b.id AND a.id=$user_data[id]");
while($secondary_referral=mysqli_fetch_array($secondary_referral_query))
{
echo '++'.$secondary_referral['users_c_username'].'<br>';
}
Your method of storing hierarchical data is called the adjacency list (model).
You have different options:
1) Read all data from database put it in a php array and traverse it recursively
Example: https://stackoverflow.com/a/15307555/1948627
2) Select only the current user and descendants, put it in a php array and traverse it recursively
The SQL should look like:
SELECT u1.username as lev1, u2.username as lev2, u3.username AS as lev3, u4.username AS as lev4
FROM users AS u1
LEFT JOIN users AS u2 ON u2.referrer = u1.id
LEFT JOIN users AS u3 ON u3.referrer = u2.id
LEFT JOIN users AS u4 ON u4.referrer = u3.id
WHERE u1.id = 1;
I didn't find examples for the php code, but it should be more difficult, because the data you receive is now redundant. Also note: For every new depth in the tree you have to add one JOIN in the DB select.
3) Recursive PHP/MySQL
Example: https://stackoverflow.com/a/10994181/1948627
I would go with option 1 if you don't have much data. Or better choose another way of storing or retrieving your data.
My favorite way are the Closure Tables
Another interesting opinion about Nested Sets: https://stackoverflow.com/a/31642680/1948627
Related
I'm having a hard time wrapping my head around the SQL I need to pull data about other users that belong to the same group as the logged in user in my PHP application.
The data structure looks like this:
User Table
user_id
name
status
bio
Group Table
group_name
user_id
What I'm trying to do is create a page that shows the bios for all of the other members of the same group or groups that a user belongs to.
I've tried this SQL:
SELECT list.listname, list.user_id, list.groupname
FROM list
LEFT JOIN user_group ON list.user_id = user_group.user_id
WHERE user_group.user_id = 'test#testuser.com'
ORDER BY list.groupname
But I just get back the bio for test#testuser.com, and no other bios. If I remove the WHERE portion of the statement, I get all bios for all users, and not just the bios of users that are in the same group as my test#testuser.com. The logged in user may belong to more than one group.
Any ideas about how to grab this data?
This returns the groups for a given user:
SELECT l.groupname
FROM list l
WHERE l.user_id = 'test#testuser.com'
ORDER BY l.groupname;
If you want all users in the groups
SELECT l.listname, l.user_id, l.groupname
FROM list l LEFT JOIN
user_group ug
ON l.user_id = ug.user_id
WHERE l.groupname IN (SELECT l2.groupname
FROM list l2
WHERE l2.user_id = 'test#testuser.com'
)
ORDER BY l.groupname;
You can do it by self-joining the list table:
SELECT l.listname, l.user_id, l.groupname
FROM list l
LEFT JOIN user_group ug ON l.user_id = ug.user_id
INNER JOIN list l2 ON l2.groupname = l.groupname
AND l2.user_id = 'test#testuser.com'
ORDER BY l.groupname;
So I currently got this query:
SELECT user_expertise.user_id, user_expertise.expertise_id
FROM user_expertise
INNER JOIN user_locations ON user_expertise.user_id = user_locations.user_id
WHERE user_expertise.expertise_id!=$exid AND user_locations.location_id = $_SESSION["user"]["location"]["location_id"]
ORDER BY user_expertise.user_id
$exid is the current id of the expertise and $_SESSION["user"]["location"]["location_id"] is the current location id retrieved from the session. For the sake of this example let's say $exid = 3981 and $_SESSION["user"]["location"]["location_id"] = 24.
I want to retrieve only the users that do not have the expertise_id of $exid (3981) attached to them. The current problem is that users that have this id attached to them get displayed when they also got another one attached to them. Let's say that user with user_id 22 has 3981 and 6523. In this case I don't want him to be part of the results but he is. At first he isn't selected because he has 3981 attached to him but then he is selected because he also has 6523 attached to him.
Update: so I got a little mad from the code used to perform the queries and reworked one of them in a new one so I can pass in a complete query string. Now I can try all of your ideas without getting a headache.
Try this:
SELECT p.user_id, p.expertise_id FROM (
SELECT s.user_id, s.expertise_id,t.expertise_id,
CASE WHEN s.expertise_id = t.expertise_id THEN 1 ELSE 0 as ind
FROM user_expertise s
INNER JOIN user_locations ss ON s.user_id = ss.user_id
CROSS JOIN user_expertise t
WHERE t.user_id = $exid
AND s.user_id <> t.user_id
AND ss.location_id = $_SESSION["user"]["location"]["location_id"]) p
GROUP BY p.user_id, p.expertise_id
HAVING MAX(p.ind) = 0
You can apply conditions to tables directly, no need to put conditions on joined result. It is also way more readable.
SELECT user_expertise.user_id, user_expertise.expertise_id
FROM user_expertise
WHERE 1=1
AND user_expertise.user_id NOT IN
(SELECT user_id FROM user_expertise WHERE expertise_id=$exid)
AND user_expertise.user_id IN
(SELECT user_id from user_locations where location_id = $_SESSION["user"]["location"]["location_id"])
ORDER BY user_expertise.user_id
I have normalized tables I want to select the items that belong to the userid
I'm familiar with select syntax but I'm very weak in joins tables so I'm a bit confused on how to get the items that belong to the user should I use join ? or is there other way
this is just simple example of my tables they have more fields
..........
user
..........
userid
firstname
address
..........
items
..........
itemsid
itemName
itemDescription
..........
user_items
..........
userid(FK)
itemsid(FK)
Use two inner join
select a.*, b.*
from user_items as c
inner join user as a on a.userid = c.userid
inner join items as b on b.itemsid = c.itemsid;
Use INNER JOIN
SQL
select user.*, items.*
from user_items
inner join user on user.userid = items.userid
inner join items on items.itemsid = user_items.itemsid;
So if I read this correctly, user_items.userid = user.userid.
So you want to join, something like this.
SELECT i.itemsid, i.itemName, i.Description FROM items i JOIN users us ON ui.userid = us.userid JOIN user_items ui ON ui.itemsid = i.itemsid WHERE ui.userid = VALUE;
Replace Value with your actuall user id
I have fetched the data from two different tables is this.
But now, I want the following result with their original names and not the numbers like status 1 is for Good, and user_id=1 means "Mike".
To select usernames using userID try using an inner join
And/or you can say 1 = good like so:
if($status == 1)
{
echo "Good";
}
(though this can also be done with the inner join, if you have the values in another table ofcourse)
Just JOIN your tables, something like:
SELECT f.FollowDate, s.StatusName, u.UserName
FROM Folowers f
INNER JOIN Users u ON f.UserId = u.ID
INNER JOIN Statuses s ON f.StatusID = s.ID
so I'm having trouble selecting a field only if another fields value is not equal to 0.
So, here's what's going on.
I have 3 tables, they are - users, schools, campuses
And basically, I need to select a single users data from these 3 tables. I'd like to only select the campus_name field from campuses if the users.campus_id field is not 0.
So, something pseudo coded like this might give you a better idea..
The query is being passed in a $id variable, that has some user's id.
SELECT users.*, schools.*, (if(users.campus_id != 0) then campuses.campus_name)
FROM users, schools, campuses
WHERE users.id = '$id' (if(users.campus_id != 0) then AND campuses.id = users.campus_id)
SELECT *
FROM schools,
users LEFT OUTER JOIN campuses
ON users.campus_id != 0
AND users.campus_id = campuses.id
WHERE users.school_id = schools.id
So you are joining three tables together, you always expect a user to have a school, but they may not have a campus, and if this is the case, obviously nothing should be displayed.
The best you can do is acheive this with a LEFT JOIN on campuses.
An example based on your pseudo code below:
SELECT u.*, s.*, c.campus_name
FROM users u
INNER JOIN schools s ON u.school_id = s.school_id
LEFT JOIN campuses c ON u.campus_id = c.campus_id
WHERE u.user_id = $userId
If I understood you correctly, you want ALL the information displayed, but to display campus name ONLY if it exists? If so, I believe the following statement should do the trick:
SELECT `u`.* `s`.* if(`c`.`campus_name` != 0, `c`.`campus_name`, "") as `campus`
FROM `users` as `u`
INNER JOIN `schools` as `s` ON `u`.`school_id` = `s`.`school_id`
LEFT JOIN `campuses` as `c` ON `u`.`campus_id` = `c`.`campus_id`
WHERE `u`.`user_id` = $user_id;
Untested, written from the top of my head, could be errors in there