Get only unique entries from pivot table in Laravel - php

I have two tables namely users and activities which has many to many relationships in my Laravel app. So, I have a pivot table activity_users with user_id and activity_id. I know that I can simply fetch all the users enrolled in an activity with a many to many relationship in my model.
But I want to get only those users from the pivot table which are enrolled in only one activity. I have been trying to do this for many days and I am still stuck. I have created a work around to filter the values based on activities_count after fetching from the database, but I wanted a more efficient solution.
Table users
id
name
1
User A
2
User B
Table activities
id
name
1
Activity 1
2
Activity 2
Table activity_users
activity_id
user_id
1
1
1
2
2
1
From this sample data what I want is: if I query for unique users in Activity 1, it should return only User B (user_id = 2) as he/she is not enrolled in other activities. And if I query for unique users in Activity 2, it should return null because it has only one user i.e. User A and he/she is already enrolled in Activity 1.
Fetching distinct values doesn't work as it just removes duplicates. I have already set to not allow duplicate combination of values in pivot table.

How about use Having?
You can find user with only one Activity like:
SELECT user_id FROM activity_users
GROUP BY user_id
HAVING count(user_id) = 1
Like Honk der Hase said in comments

Providing some code would help, if only to show more information on your relationships between models. But at a guess I think something like this should work:
$users = User::with("activities")
->withCount("activities")
->having("activities_count", 1)
->whereHas("activities", fn ($q) => $q->where("activities.id", $activity_id));
We eager load the activities relationship and get the count as an alias, so we can catch only those with a single activity. Then we filter the relationship to search for the provided activity id.
This assumes you've set up your User and Activity models with a proper many-to-many relationship.
For completeness, the resulting typically (for Laravel) verbose SQL is:
SELECT `users`.*, (
SELECT COUNT(*)
FROM `activities`
INNER JOIN `activity_user` ON `activities`.`id` = `activity_user`.`activity_id`
WHERE `users`.`id` = `activity_user`.`user_id`
) AS `activities_count`
FROM `users` WHERE EXISTS (
SELECT * from `activities`
INNER JOIN `activity_user` ON `activities`.`id` = `activity_user`.`activity_id`
WHERE `users`.`id` = `activity_user`.`user_id`
AND `activities`.`id` = ?
)
HAVING `activities_count` = ?

Related

Eloquent/Query builder Laravel: Select from table A without exists in table B

I have 3 table as below:
User: id, name
Room: id, room_name
User_Room: user_id, room_id
How can I select all user from table User, without user exist in Table Room_User ?
I already followed with this post but I don't know how to convert query below to Eloquent or Query Building
select A.*
from A left join B on A.BAND = B.HATE
where B.HATE IS NULL;
Please help.
If you have a Many to Many relationship between the tow Models then you can simply use doesntHave method (Querying Relationship Absence section) :
$users = User::doesntHave('rooms')->get();

Show a group project to multiple users mysql

I have two tables the group_table where all the groups information is stored.
And i have a group_person_table where all id's which correlate to groups
I only want to display the group information to multiple users if they match in group_person_table
the database looks like this :
Group_table
person_id, group_id, groupname, groupdesc.
Group_person_table
person_group_id, group_id, person_id
currently i only have the following query:
"SELECT * FROM group_table WHERE person_id = $person_id" IN (SELECT person_id FROM group_person_table WHERE person_id =$person_id);
I currently am able to display all of the groups to all of the users but i only want to display the groups to the users if they're the same in group_person_table so user A and B are in group A so they both see Group A, if user A is in Group B, then User B wont see group B!
I'm displaying calling upon the data in OOP
public function get_project($person_id){
//$sql3="SELECT * FROM group_table WHERE person_id = $person_id ";
$sql3="SELECT * FROM group_table WHERE person_id = $person_id";
$results = mysqli_query($this->db, $sql3);
One very important thing when creating a relation between tables is to decide where to keep the foreign key that will be used for linking them. Having a foreign key to the persons table in the group table, would restrict the group to one person only, which you obviously don't want. So, you can remove that column from the group_table and use only the group_person_table for the relations between the users and groups.
After adjusting this, your best choice would be an inner join, because nested select statements can really slow things down when working with larger data sets. And you want to get used to using the better approach :).
Your query would then be:
"SELECT * FROM group_table
JOIN group_person_table ON group_table.group_id = group_person_table.group_id
WHERE group_person_table.person_id = {$person_id}"

filtering sql search by two variables having same result

I'm not sure how I can do this but I have two tables:
--users--
id_users (index)
name_users
--friend--
id_friend (index)
id_user (connects to id_users)
linked_friend (also links to id_users as this is the id of the requested friend)
for a friendship to be requested one row exists with the user who requested in friend.id_user col and the user they are requesting being in the friend.linked_friend col. To confirm the friendship link another row is created with the info reversed so that there are two rows for each friendship with each user being in the friend.id_user AND the friend.linked_friend col. (let me know if I could do this in a better way)
so what I need to do is for each user list all users on the system that are in a confirmed friendship (two rows) and aren't themselves.
SELECT id_user, name_user FROM user WHERE id_user <> $userId
obviously removes themselves from the list but I'm at a loss as to how to select users that have both rows.
I hope that is clear enough.
Thanks
You could join the friend table twice to demand that rows in both direction exist:
select u1.name
, u2.name
from users u1
join friend f1
on u1.id_users = f1.id_user
join friend f2
on f2.id_user = f1.linked_friend
and f2.linked_friend = f1.id_user
join users u2
on u2.is_users = f2.id_user
and u1.id_users < u2.id_users -- Display friends once
I agree with Jack Pettinger that this design is fairly clunky. There should be only one row in the friends table for each relation. It should have a unique constraint to enforce that, like:
alter table Friends add constraint CHK_Friend check (friend1_id < friend2_id);
create index UX_Friends on Friends (friend1_id, friend2_id);
you have to use Join if you want to fetch data from two or more tables.
Try this
select * from users left join friend on users.id_users = friend.id_user
// you also give where condition for particular user_id

Can i separate data in a mysql row with "," and decipher that data?

Okay I am making a profile page where I will call on all of the user's information. Within the website users will gain points and earn badges. I have something like 35 badges. Rather than have a row in my users table for every badge(yes/no to decide whether user has earned badge) for every single user, I was wondering how I could do this without blowing up my users table.
I have a badge table with index, name, description, and photo. I was wondering can I make a single row in my users table for badges and separate badge numbers by ",". Then decipher the badges so they all print on the page. I feel I can do this but don't know how.
Please help. Open to other suggestions
You are describing a many-to-many relationship; use a junction table to represent it.
Create a table of users and a table of badges. Then create a Users_Badges table with user_id and badge_id as foreign keys in it (together they will form a composite key).
you can create table structures like these.
table structures
users
userId
userName
badges
badgeId
badgeName
user_badges
userId
badgeID
-- returns given users all badges within single row and comma seperated field.
select group_concat(b.badgeName) as usersAllBadges
from user_badges ub
inner join users u on u.userId = ub.userId
inner join badges b on b.badgeId = ub.badgeID
where ub.userID=1
-- returns given users all badges seperate rows.
select b.badgeName
from user_badges ub
inner join users u on u.userId = ub.userId
inner join badges b on b.badgeId = ub.badgeID
where ub.userID=1
You tagged php so I am assuming php
explode(',',$data);
http://www.php.net

Getting users based on group, but users, user_groups and groups kept in separate tables

I'm assuming I need to use JOIN, but I'm not totally getting it. Here's my situation. I'm using ion_auth. It stores users in 'users', groups in 'groups' and stores users' group in 'users_groups'.
So if I have a group 'sales' with an id of '2', any user associated with that group appears in 'users_groups' as:
id user_id group_id
1 1 2
1 2 2
So how can I quickly return the results of a query like: get users from group 2. Would the JOIN command be what I'm looking for? I'm using CodeIgniter's Active Record but am open to any suggestions.
It's a very basic join between two tables
SELECT users.* FROM users JOIN users_groups ON (users.id=users_groups.user_id) WHERE users_groups.group_id = 2
SELECT list_of_fields FROM users JOIN users_group USING (group_id) WHERE users.group_id = 2
Assuming you used group_id as the field name on both tables

Categories