181

How can I make this query in Laravel:

SELECT 
    `p`.`id`,
    `p`.`name`, 
    `p`.`img`, 
    `p`.`safe_name`, 
    `p`.`sku`, 
    `p`.`productstatusid` 
FROM `products` p 
WHERE `p`.`id` IN (
    SELECT 
        `product_id` 
    FROM `product_category`
    WHERE `category_id` IN ('223', '15')
)
AND `p`.`active`=1

I could also do this with a join, but I need this format for performance.

Madan Sapkota
  • 25,047
  • 11
  • 113
  • 117
Marc Buurke
  • 1,917
  • 2
  • 13
  • 14

12 Answers12

273

Consider this code:

Products::whereIn('id', function($query){
    $query->select('paper_type_id')
    ->from(with(new ProductCategory)->getTable())
    ->whereIn('category_id', ['223', '15'])
    ->where('active', 1);
})->get();
giannis christofakis
  • 8,201
  • 4
  • 54
  • 65
lukaserat
  • 4,768
  • 1
  • 25
  • 36
88

Have a look at the advanced where clause documentation for Fluent. Here's an example of what you're trying to achieve:

DB::table('users')
    ->whereIn('id', function($query)
    {
        $query->select(DB::raw(1))
              ->from('orders')
              ->whereRaw('orders.user_id = users.id');
    })
    ->get();

This will produce:

select * from users where id in (
    select 1 from orders where orders.user_id = users.id
)
Community
  • 1
  • 1
drewjoh
  • 1,786
  • 1
  • 14
  • 22
  • That comes close, and i've been puzzeling with similar queries for some time now. But where_in (laravel 3) requires 2 arguments, the second one being an array. Any idea how to get this right? Also, I don't think laravel 3 supports the from method. – Marc Buurke May 29 '13 at 14:11
  • Ah, Laravel3... Yeah, that's going to be difficult then. And I think in Laravel3 you use the `table()` method instead of the `from()`. I haven't had that situation in L3, sorry! – drewjoh May 29 '13 at 14:35
  • I can't see a whereIn method which takes a lambda in Illuminate\Database\Query\Builder has it been renamed whereSub? – nbransby Nov 12 '13 at 17:49
26

You can use variable by using keyword "use ($category_id)"

$category_id = array('223','15');
Products::whereIn('id', function($query) use ($category_id){
   $query->select('paper_type_id')
     ->from(with(new ProductCategory)->getTable())
     ->whereIn('category_id', $category_id )
     ->where('active', 1);
})->get();
Ramesh
  • 1,829
  • 2
  • 25
  • 30
12

Here is my approach for Laravel 8.x gathered from multiple answers here:

  • Use the query builder and don't write SQL directly.
  • Use the models and determine everything from there. Don't use a hardcoded table name, or any name (columns, and so on) for that matter.
Product::select(['id', 'name', 'img', 'safe_name', 'sku', 'productstatusid'])
    ->whereIn('id', ProductCategory::select(['product_id'])
        ->whereIn('category_id', ['223', '15'])
    )
    ->where('active', 1)
    ->get();
Darkproduct
  • 1,062
  • 13
  • 28
11

You can use Eloquent in different queries and make things easier to understand and mantain:

$productCategory = ProductCategory::whereIn('category_id', ['223', '15'])
                   ->select('product_id'); //don't need ->get() or ->first()

and then we put all together:

Products::whereIn('id', $productCategory)
          ->where('active', 1)
          ->select('id', 'name', 'img', 'safe_name', 'sku', 'productstatusid')
          ->get();//runs all queries at once

This will generate the same query that you wrote in your question.

Philipe
  • 121
  • 1
  • 4
7

The script is tested in Laravel 5.x and 6.x. The static closure can improve performance in some cases.

Product::select(['id', 'name', 'img', 'safe_name', 'sku', 'productstatusid'])
            ->whereIn('id', static function ($query) {
                $query->select(['product_id'])
                    ->from((new ProductCategory)->getTable())
                    ->whereIn('category_id', [15, 223]);
            })
            ->where('active', 1)
            ->get();

generates the SQL

SELECT `id`, `name`, `img`, `safe_name`, `sku`, `productstatusid` FROM `products` 
WHERE `id` IN (SELECT `product_id` FROM `product_category` WHERE 
`category_id` IN (?, ?)) AND `active` = ?
Madan Sapkota
  • 25,047
  • 11
  • 113
  • 117
6

The following code worked for me:

$result=DB::table('tablename')
->whereIn('columnName',function ($query) {
                $query->select('columnName2')->from('tableName2')
                ->Where('columnCondition','=','valueRequired');

            })
->get();
Aditya Singh
  • 704
  • 2
  • 12
  • 20
1

Laravel 4.2 and beyond, may use try relationship querying:-

Products::whereHas('product_category', function($query) {
$query->whereIn('category_id', ['223', '15']);
});

public function product_category() {
return $this->hasMany('product_category', 'product_id');
}
LC Yoong
  • 1,772
  • 3
  • 15
  • 19
1
Product::from('products as p')
->join('product_category as pc','p.id','=','pc.product_id')
->select('p.*')
->where('p.active',1)
->whereIn('pc.category_id', ['223', '15'])
->get();
panqingqiang
  • 167
  • 1
  • 2
-1

using a variable

$array_IN=Dev_Table::where('id',1)->select('tabl2_id')->get();
$sel_table2=Dev_Table2::WhereIn('id',$array_IN)->get();
a3rxander
  • 868
  • 2
  • 10
  • 17
  • 1
    This will result in two querys and not just one. You can insert the first query builder into the second one, without getting the result of the first quary. See Philipes answer for more details. – Darkproduct Apr 08 '21 at 12:17
-1

You use DB::raw to set subquery.

Example

DB::raw('(
    SELECT 
    `product_id` 
    FROM `product_category`
    WHERE `category_id` IN ('223', '15') as `product_id`
')
Abeysinghe
  • 19
  • 4
-4

Please try this online tool sql2builder

DB::table('products')
    ->whereIn('products.id',function($query) {
                            DB::table('product_category')
                            ->whereIn('category_id',['223','15'])
                            ->select('product_id');
                        })
    ->where('products.active',1)
    ->select('products.id','products.name','products.img','products.safe_name','products.sku','products.productstatusid')
    ->get();
liquid207
  • 176
  • 5