0

I have the following query where I want to select distinct rows. However the count query generated by the paginator does not seem to add the distinct clause and so I'm getting an incorrect total?

DB::enableQueryLog();

$jobs =  Job::join('locations', 'locations.id', '=', 'jobs.location_id')
            ->join('job_industry', 'job_industry.job_id', '=', 'jobs.id')
            ->select('jobs.*', 'locations.name')
            ->distinct()
            ->paginate(5, 'jobs.id');

 dd(DB::getQueryLog());

This is the query log:

"query" => """
    select count(*) as aggregate from `jobs`
     inner join `locations` on `locations`.`id` = `jobs`.`location_id`
     inner join `job_industry` on `job_industry`.`job_id` = `jobs`.`id`

  """


"query" => """
    select distinct `jobs`.*, `locations`.`name` from `jobs`
     inner join `locations` on `locations`.`id` = `jobs`.`location_id`
     inner join `job_industry` on `job_industry`.`job_id` = `jobs`.`id`
    limit 5 offset 0
  """

As you can see the count query generated by the paginator method is incorrect - it should be COUNT(DISTINCT jobs.id) as aggregate...

I followed the instruction from the following post (distinct() with pagination() in laravel 5.2 not working) but I cant find the following code referenced in the above post inside my copy of builder.php - this can be confirmed by checking the master repo: https://github.com/laravel/framework/blob/5.2/src/Illuminate/Database/Eloquent/Builder.php#L484

 //To solved paginator issue with distinct...
if(is_null($columns) && strpos($this->toSql(), 'distinct') !== FALSE){
    $columns = $this->columns; 
    $columns = array_filter($columns, function($value) {
        return (is_string($value) && !empty($value));
    });
}
else {
    //If null $column, set with default one
    if(is_null($columns)){
        $columns = ['*'];
    }
}

I tried to add the above code to my own paginate method inside the builder.php file but it makes no difference - I still get the same behavior?

How do I fix this. The only way I can overcome this is by using a group by clause but then that has its own performance issues.

adam78
  • 9,668
  • 24
  • 96
  • 207
  • 2
    Long shot here, but can you try to put inside brackets? `->paginate(5, ['jobs.id']);` – Felippe Duarte Aug 15 '17 at 17:20
  • @Felippe Duarte already tried that and it doesnt work. I don't think this issue has ever been fixed reading through all these posts: https://github.com/laravel/framework/pull/4088 unless anyone has any other suggestions? – adam78 Aug 15 '17 at 17:30
  • 1
    One suggestion would be to replace the DISTINCT clause with a groupBy approach. – Felippe Duarte Aug 15 '17 at 17:34
  • @FelippeDuarte yeah I already mentioned that at the bottom of my post but groupby has its own performance issues and strictly speaking doesn't read well since the query isn't really doing an aggregate. – adam78 Aug 15 '17 at 17:37
  • @adam78 did you ever fix this? I'm struggling with this right now. – helsont Jun 08 '18 at 17:50
  • 1
    @FelippeDuarte You saved the day here! Your example clarified another solution with * that did not work. Thanks a lot man! – André Luiz Müller Aug 29 '18 at 18:34

1 Answers1

4

I encountered similar problem before. I fixed it by doing this :

->distinct('jobs.id')
->paginate(5, 'jobs.id');
exceptione
  • 101
  • 1
  • 18
  • This worked for me but without needing to enter the column name into the paginate method. The distinct argument was all I needed, which is extra confusing because looking at the source code it doesn't appear to accept arguments https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Query/Builder.php#L437 – coderp Mar 17 '23 at 14:00