I have a many-to-many table which is named with "users_groups". With this table I want to assign the unique user_id to a group_id. This works pretty well but now I want to make a panel which shows in which groups the current user is and what users are in these groups.
This is my current code for getting all groups with the users of them.
MySQL-Part
$all_groups = mysqli_query
($db,
"SELECT group_name,GROUP_CONCAT(realname SEPARATOR ', ') AS users
FROM groups
JOIN users_groups ON groups.group_id=users_groups.group_id
JOIN users ON users_groups.user_id=users.user_id
GROUP BY group_name
"
);
PHP-Part
echo'
<table class="table_standard">
<tr>
<th class="th_titlebar">Group</th>
<th class="th_titlebar">Members</th>
</tr>';
while($row_all_groups = mysqli_fetch_array($all_groups)) {
echo '<tr>';
echo '<td class="td_contentbar">'.$row_all_groups["group_name"].'</td>';
echo '<td class="td_contentbar">'.$row_all_groups["users"].'</td>';
echo '</tr>';
}
echo '</table>';
And now I have no idea how to include the WHERE-Part in the MySQL. I tried it already with WHERE users_groups.user_id = $session_user_id but with this method the member lists of the groups were just filled with the current user.
My next idea was to make a first MySQL-Request like SELECT group_id FROM users_groups WHERE user_id=$user_id which safes the group_id's in an array and so on but this did not work for me, no idea why.
You can use a sub select and an additional join for your junction table to get only groups #session_user_id has an association and in GROUP_CONCAT part get all members from the resultant groups
SELECT g.group_name,GROUP_CONCAT(DISTINCT u.realname SEPARATOR ', ') AS users
FROM groups g
JOIN (SELECT * FROM users_groups WHERE user_id =#session_user_id) ug
ON g.group_id=ug.group_id
JOIN users_groups ug1 ON g.group_id=ug1.group_id
JOIN users u ON ug1.user_id=u.user_id
GROUP BY g.group_name
DEMO
Are you trying to get it show what usergroup the current logged in user is in?
If so then this would be your sql based on the above:
SELECT group_name,GROUP_CONCAT(realname SEPARATOR ', ') AS users
FROM users
JOIN users_groups ON users_groups.user_id = users.user_id
JOIN groups ON groups.group_id = users_groups.group_id
WHERE users.user_id = $session_user_id
GROUP BY groups.group_id
That should return a result with all the all the groups and the current user. To remove this repeating User if you was to just show the current groups the current user is assigned to then remove the realname part from the select and just have the group_name.
shows in which groups the current user is and what users are in these groups.
the groups the current user is in:
SELECT g.group_name
FROM groups g
JOIN users_groups ug
ON ug.group_id = g.group_id
WHERE ug.user_id = :session_user_id
ORDER BY g.group_name
To get a list of users that are in those groups, we need another join to the users_groups table. We can also add the join to the users table to get the information for those users...
-- og = other user_id that are in a a group
-- ou = info about those other users
SELECT g.group_name
, ou.user_id
, ou.realname
FROM groups g
JOIN users_groups ug
ON ug.group_id = g.group_id
JOIN users_groups og
ON og.group_id = g.group_id
JOIN users ou
ON ou.user_id = og.user_id
WHERE ug.user_id = :session_user_id
ORDER BY g.group_name, ou.user_id
If you want to omit the current user from the list of users, you can add an inequality predicate.
If you want to collapse that to a single row for each group, you can use the GROUP BY clause and the GROUP_CONCAT function, as in your first query. For a more deterministic result, consider adding an ORDER BY in the GROUP_CONCAT. Beware of the group_concat_max_len setting, which limits the size of the string returned.
Related
I have 3 tables:
miners with columns id and name;
users with columns id, name and password;
user_miners with columns user_id and miner_id (foreign key to those other tables)
I need to print out users and their miner names
so for example i have user with id 1, and he has miners with names f,s,t
So i would need to print out:
1 f
1 s
1 t
how do i do that using left join?
I've tried all the possible left joins but i cant seem to get it working, maybe simply because i don't understand the concept of left join
('SELECT user_mineres.user_id, users.id, miners.name
FROM user_mineres
LEFT JOIN users
ON user_mineres.user_id=users.id
LEFT JOIN miners
ON users.id=miners.name
GROUP BY user_mineres.user_id ');
foreach ($stmt as $row)
{
echo $row['user_id'] . $row['name'] . "<br>";
}
i get errors that the column names are ambiguous or other syntax errors
You don't need a group by, only the proper joins and the proper ON clauses:
SELECT u.id, m.name
FROM users u
LEFT JOIN user_miners um ON um.user_id = u.id
LEFT JOIN miners m ON m.id = um.miner_id
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;
I have two tables: publick_feed and users
I want to SELECT all from public_feed and also SELECT a three columns from users whose id is the same of user_id in public_feed
and assign the rows returned from public_feed to the column in users table ( correspondent)
I try this:
<?php
$sql = "
SELECT * FROM public_feed
WHERE user_id IN
(SELECT id FROM users) AND
(SELECT Firstname,Lastname,Avatar FROM users WHERE id IN(SELECT user_id FROM public_feed))
";
$query = mysqli_query($dbc_conn,$sql);
if(mysqli_num_rows($query) > 0){
while($row = mysqli_fetch_assoc($query)){
//echo rows with correspondent details from the users table
echo $row['user_id'];
}
}
<?
Please any help will be much appreciated.
Thank you.
Or version with left join in case if there is no user in public_feed, and you still want to fetch user data
SELECT
u.*, f.*
FROM
public_feed f LEFT JOIN
users u ON f.user_id = u.id;
Because author asked for explanation, here it is:
First we are going to use table name alias to make query shorter
public_feed f
and
users u
we are saying that want to refer to tables with an alias. Of course * means that we want to select all columns
SELECT users.*, public_feed.*
is equal to
SELECT u.*, f.*
Of course you can use any other letters as an alias
Next we are saying that public_feed.user_id must be equal to users.id. But when public feed entry does not exists just display columns with null values. This is why we are using LEFT JOIN instead of INNER JOIN. In general JOINS are used to fetch related data from more than one related tables.
ON keyword is saying values from which columns in the tables must be equal to satisfy the request
I think doing a join would be cleaner than using a complicated subquery:
SELECT u.Firstname,
u.Lastname,
u.Avatar,
COALESCE(pf.User_id, 'NA'),
COALESCE(pf.Post, 'NA'),
COALESCE(pf.Date, 'NA')
FROM users u
LEFT JOIN public_feed pf
ON u.Id = pf.User_id
I chose a LEFT JOIN of users against public_feed on the assumption that every feed will have an entry in the users table, but not necessarily vice-versa. For those users who have no feed entries, NA would appear in those columns and that user would appear in only a single record.
I'm creating a social mobile-application which has groups and groups can have user. I'm trying to write a query in order to get all the groups along with number of users in it.
Note: Group can have 0 users as well.
Even if group has zero user, I still need to get its information. How should I do that? I tried:
Select *, count(ug.group_id) from groups g
left join images i ON(g.group_image_id = i.image_id)
left join location l ON(g.group_location_id = l.location_id)
.
.
left join user_group ug on(ug.gorup_id = g.group_id)
group by ug.group_id;
Now, this query does not give me group that has zero user(s). How can change it so it shows all group even if group has 0 users.
Using SELECT * and GROUP BY is a MySQL abomination. In your case, it doesn't look like it hurts since image and location appear to have a 0:1 relation ship with group. It's just very bad practice.
Here's an ANSI compliant way to write your query. If you want the full result set from JOINing a few tables, plus the count, then add only the count portion as an expression.
Select *, (select count(ug.group_id)
from user_group ug
where ug.gorup_id = g.group_id) GroupUserCount
from groups g
left join images i ON(g.group_image_id = i.image_id)
left join location l ON(g.group_location_id = l.location_id)
.
.
you should group them from groups table
GROUP BY g.group_id
I believe you are looking for something like:
Select g.group_id,coalesce(users ,0)
from groups g
left join (select ug.gorup_id,count(*) users
from user_group ug
group by ug.gorup_id) s
on s.group_id = g.group_id
If you only need to know the group and number of users, the other table in the example are not necessary.
Your are grouping by a column of your left join, this means that your are grouping by null when a group have no users.
You need to group by id of the groups table and the count(*) will count the number of joined rows.
Then add the empty groups using a left join and where join row is null
Select g.group_id as groupId, count(*) as nb
from groups g
join user_group ug on (ug.group_id = g.group_id)
group by g.group_id
UNION ALL
Select g.group_id as groupId, 0 as nb
from groups g
left join user_group ug on (ug.group_id = g.group_id)
where ug.group_id is null
group by g.group_id
[EDIT] One query count looking for null join in the select statement and setting nb to 0 if found
Select g.group_id as groupId, IF(ug.group_id is null, 0,count(*)) as nb
from groups g
left join user_group ug on (ug.group_id = g.group_id)
group by g.group_id
I am making simple connection between two table - first one called users has fields :
|| id || name ||
and the second table called groups has the same fields:
|| id || name ||
The relations b/w them is many to mane because one user can be in many groups(of interest) and a group will contain more than one user. So I have a third table user_group with fields:
|| user_id || group_id ||
Where the both are foregin keys one for users and one for groups.
The goal is to make a list with all the groups and the people participating in each one.
For this I made my query:
$q = $this->db->query('SELECT u.name FROM users u
JOIN user_group ug ON u.id = ug.user_id
JOIN groups g ON g.id = ug.group_id WHERE ug.group_id = "4" ');
then modified it using active records:
$this->db->select('users.name');
$this->db->from('users');
$this->db->join('user_group', 'user_group.user_id = users.id');
$this->db->join('groups', 'groups.id = user_group.group_id');
$this->db->where('user_group.group_id', 3);
$q = $this->db->get();
And this way I can take the users for any group by given the 'id' from the group table. But what I can't figure out is how to make it display both - the name of the group along with the users participating. When I create and delete from the tables the id's become very unorder I may have 20 groups and some group may have id = 53 so jsut looping from 1 to number_of_groups is not good enough. What's the way to do this?
Thanks
Leron
You cannot get the group as well as the users in that group all in one query. You could get the concatenated user list for each group in one query
SELECT g.group_name, GROUP_CONCAT(u.fullname)
FROM group g
JOIN user_group ug ON g.id = ug.id
JOIN user u ON ug.user_id = u.id
GROUP BY g.id
The group => user is Many to Many relation so a user in a group will return multiple rows for users.
If you need the list of the user details as well and not the concatenated form.
You can iterate over the group list and then add a key to the users.
$groups = $this->db->get('groups')->result();
foreach($group as &$g){
$this->db->select('users.name');
$this->db->from('users');
$this->db->join('user_group', 'user_group.user_id = users.id');
$this->db->where('user_group.group_id', $g->id);
$g->users = $this->db->get()->result();
}
Now you loop through $group and can access the users with $group->users
Notice that & before $g in the foreach loop. Since foreach operates over the copy of the variable being passed, you have pass the reference to it.
Just select the group name too, you just have to alias the field name:
$q = $this->db->query('SELECT u.name, g.name AS `group_name` FROM users u
JOIN user_group ug ON u.id = ug.user_id
JOIN groups g ON g.id = ug.group_id WHERE ug.group_id = "4" ');