Home > OS >  Get only unique entries from pivot table in Laravel
Get only unique entries from pivot table in Laravel

Time:08-17

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.

CodePudding user response:

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

CodePudding user response:

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