Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Kimmer's avatar

One result from Count Distinct on multiple tables

For the app I'm building I have in my database

A table named "listings"

| id | 
-------
|  1 |

A table named "tracks".

| id | listing_id | user_id |
-----------------------------
|  1 |     1      |    1    |
|  2 |     1      |    1    |
|  3 |     1      |    1    |
|  4 |     1      |    1    |

A table named "votes".

| id | listing_id | user_id |
-----------------------------
|  1 |     1      |    1    |
|  2 |     1      |    2    |
|  3 |     1      |    2    |

For my administration page I'm creating a sortable table that should show (among other data) the number of contributors. So the number of users that have added tracks or voted. In the tables above you see that user 1 (4 tracks, 1 vote) and user 2 (2 votes) contributed to the list. The result should be 2.

This is my query now:

$query = Listing::query();

return $query
        ->leftJoin('tracks', 'tracks.listing_id', '=', 'listings.id')
        ->leftJoin('votes', 'votes.listing_id', '=', 'listings.id')
        ->selectRaw('listings.*,
                    count(DISTINCT tracks.user_id + votes.user_id) as contributors
                    ')
        ->groupBy('listings.id')
        ->orderBy($sortBy,$descending)
        ->paginate( $limit );

This results in 3 contributors. So the query is counting user_id 1 twice.

Does anyone have an idea how to solve this?

Thanks!

0 likes
13 replies
Kimmer's avatar

BTW this is my full query at the moment

 $query = Listing::query();

return $query
        ->leftJoin('users', 'user_id', '=', 'users.id')
        ->leftJoin('tracks', 'tracks.listing_id', '=', 'listings.id')
        ->leftJoin('votes', 'votes.listing_id', '=', 'listings.id')
        ->selectRaw('listings.*,
                    users.name,
                    count(DISTINCT tracks.id) as tracks,
                    count(DISTINCT votes.id) as votes,
                    count(DISTINCT tracks.user_id + votes.user_id) as contributors
                    ')
        ->groupBy('listings.id')
        ->orderBy($sortBy,$descending)
        ->paginate( $limit );

It gives me sortable tracks and votes count but a wrong contributors count as described above

Kimmer's avatar

Hehe, yeah, I only ask complex issues. I can do the simple once or find a solution for those ;-) I usually take a couple of hours of searching before I post a question.

Thanks for the link. I noticed before it might have something to do with UNION but I'm still unable to incorporate it on the flow that I have.

Not the most important part of my project. I'll come back to it later.

staudenmeir's avatar

This monstrosity works for me:

select *,
  (
    select count(*)
    from (
      select listing_id, user_id from tracks group by listing_id, user_id
      union
      select listing_id, user_id from votes group by listing_id, user_id
    ) alias
    where listing_id = listings.id
  ) contributors
from listings
1 like
Kimmer's avatar

Thanks! Really appreciate your time and effort but I'm unable to incorporate that into what I already have. Or even make it work on it's own in my controller

Kimmer's avatar

MySQL but the problem is that I don't know how to incorporate your code in the Laravel/Eloquent code I already have working (see a couple of messages above).

BTW: I can also not see the DB-Fiddle

staudenmeir's avatar

Does the query work in your database?

Is the fiddle empty?

Kimmer's avatar

I'm sorry, I didn't realise I could test the query in PHPMyAdmin. Still learning every day. When I do that it seems to work indeed.

The link to the fiddle redirects to an empty fiddle: https://www.db-fiddle.com/

staudenmeir's avatar

What does your query code look like at the moment? What exactly isn't working?

Kimmer's avatar

I posted it a couple of messages above but here it is again:

$query = Listing::query();

return $query
        ->leftJoin('users', 'user_id', '=', 'users.id')
        ->leftJoin('tracks', 'tracks.listing_id', '=', 'listings.id')
        ->leftJoin('votes', 'votes.listing_id', '=', 'listings.id')
        ->selectRaw('listings.*,
                    users.name,
                    count(DISTINCT tracks.id) as tracks,
                    count(DISTINCT votes.id) as votes,
                    count(DISTINCT tracks.user_id + votes.user_id) as contributors
                    ')
        ->groupBy('listings.id')
        ->orderBy($sortBy,$descending)
        ->paginate( $limit );

The line for "contributors" is the one that doesn't work. I expanded the "selectRaw" code for some more results with a couple of similar counts but nothing relevant for this issue.

staudenmeir's avatar
Level 24

What I meant: What does your approach to integrating my query look like?

It works for me if I replace count(DISTINCT tracks.user_id + votes.user_id) as contributors with (select count(*) from [...] where listing_id = listings.id) as contributors

1 like
Kimmer's avatar

I tried some combinations which resulted in MySQL errors but not the one you've suggested. Indeed this seems to work. Eventually it was a matter of brackets

Honestly, I kind-of gave on on it myself. Your patience is super natural. Thanks you so much.

Please or to participate in this conversation.