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

jsartisan's avatar

Complex Eloquent Relationship DB Selections

HI all, please help me out with this problem.

I have a labs table and lab_test table. A Lab can have multiple tests.

i want only those labs having all tests given in array

public function getLabsHavingTests($tests)
    {
        // $tests is an array having test_ids
        // $tests is like this => [1,3]
        // should return only those labs having all tests giving in $tests
    }
0 likes
36 replies
kfirba's avatar

@jsartisan Maybe try something like:

Lab::whereHas('tests', function ($q) uses ($tests) {
    $q->whereIn('test_id', $tests);
})->get();
jsartisan's avatar

@kfirba @veve286 its returning all labs having any of $tests specified.

Suppose $tests => [1,3]

the code should return all labs having both test 1 and test 3 . Your code is returning labs having either test 1 or test 3.

veve286's avatar
Lab::whereHas('tests', function ($q) uses ($tests) {
    
foreach($tests as $test){
        $q->where('test_id', $test);
    }
 
})->get();
1 like
jsartisan's avatar

@veve286 i have tried this. It returns empty array.

because its looks for something lke this "select * from lab_test where test_id = 1 and test_id = 3" which doesn't make any sense.

veve286's avatar

try this . If it donesn't work , show me your Lab and lab_test model.

Lab::whereHas('lab_test', function ($q) uses ($tests) {
    
foreach($tests as $test){
        $q->where('id', $test);
    }
 
})->get();
jsartisan's avatar

Test.php

class Test extends Model{

    protected $fillable = ['name', 'description'];


}

Lab.php

class Lab extends Model{

    protected $fillable = ['name', 'location_id', 'phone','description'];
    
    public function tests()
     {
            return $this->belongsToMany('App\Models\Test');
        }
}

veve286's avatar

Is it work ?

Lab::whereHas('test', function ($q) uses ($tests) {
    
foreach($tests as $test){
        $q->where('id', $test);
    }
 
})->get();
jsartisan's avatar

This gives this error : "Call to undefined method Illuminate\Database\Query\Builder::test()"

willvincent's avatar

So, Labs have many tests, and a single test belongs to one lab, right?

I think you've got your relationship set up wrong

2 likes
veve286's avatar

sorry typo error. I forget 's' in whereHas

Lab::whereHas('tests', function ($q) uses ($tests) {
    
foreach($tests as $test){
        $q->where('id', $test);
    }
 
})->get();

veve286's avatar

@willvincent yes u r right . His model is also wrong. Change ur model relation like this.

public function test()
{
    return $this->hasMany('App\Models\Test');
}
jsartisan's avatar

A Weird Error.

Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous (SQL: select count() as aggregate from labs where (select count() from tests inner join lab_test on tests.id = lab_test.test_id where lab_test.dc_id = labs.id and id = 1 and id = 3) >= 1)

jsartisan's avatar

@willvincent

I'm not using the inverse relationship. So i didn't add that relationship. But since you asked, i added this in Test.php

public function labs()
    {
      return $this->belongsToMany('App\Models\Lab');
    }
veve286's avatar

sorry again. Try this . If it doesn't work i have no idea :)

Lab::whereHas('tests', function ($q) uses ($tests) {
    
foreach($tests as $test){
        $q->where('test_id', $test);
    }
 
})->get();
veve286's avatar

Have you already changed your Lab relation to has Many ?

public function test()
{
    return $this->hasMany('App\Models\Test');
}
veve286's avatar

Ok got it Try this Lab::whereHas('tests', function ($q) uses ($tests) {

foreach($tests as $test){ $q->where('lab_test.test_id', $test); }

})->get();

thomaskim's avatar

Why would you create a pivot table for such a simple relationship? Unless we're missing something, willvincent is right. A lab can have multiple tests. Each test belongs to one lab. That is a one-to-many relationship.

jsartisan's avatar

@thomaskim User is searching labs according to tests. So for e.g. "A blood test" can be available to multiple labs and a labs can have many tests. Thats why i needed a pivot table.

1 like
jsartisan's avatar

id | test_id | price | lab_id | discount | is_home_collectable | created_at | updated_at

here are the columns for the pivot table.

veve286's avatar

i means screenshot of pivot table that contains data :D

thomaskim's avatar

@jsartisan Oh okay. :) Try this then. Have you tried adjusting kfirba's post a little bit like this?

Lab::whereHas('tests', function ($q) uses ($tests) {
    $q->whereIn('id', $tests);
})->get();
jsartisan's avatar

yes i have. test_id in lab_test is referencing to the id of test table.

lab_test.test_id --------> tests.id

Next

Please or to participate in this conversation.