简体   繁体   中英

SQL query to Laravel query builder

I have 2 tables

risks

risk_id    name    area_id
1          a       1
2          b       1

risk_areas

id         name    parent_id
1          a       0
2          b       1
3          c       1
4          d       2

This is my sql query:

SELECT * FROM `risks` WHERE (`register_id` = 29 AND `area_id` = 1) 
OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id = 1) AND `register_id` = 29 ) 
OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id IN (SELECT id FROM risk_areas WHERE parent_id = 1)) AND `register_id` = 29 ) 

When run in phpMyAdmin the query works as expected.

I've been trying to implement it into Laravel using the query builder. It fetches a risk from a certain register (I've used 29 for an example) and also finds all of its children risks (there can only be up to 3 generations eg parent->child->child)

I intially tried this:

$query-> raw("
    SELECT * FROM `risks` WHERE (`register_id` = " . $q['register_id'] . "  AND `area_id` = ".$q['area_id'].") 
    OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id = ".$q['area_id'].") AND `register_id` = " . $q['register_id'] . " ) 
    OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id IN (SELECT id FROM risk_areas WHERE parent_id = ".$q['area_id'].")) AND `register_id` =  " . $q['register_id'] . " ) 
");

$q['register_id'] fetches the register_id and $q['area_id'] fetches the area_id correctly.

Since that didn't work (it just outputted the parents and even the ones with the same area_id but different register ids) I tried this:

$query
    ->where('area_id', $q['area_id'])
    ->orWhere('area_id','IN',  function ($query) use($q) {
        $query->where('parent_id',$q['area_id'])
            ->where('register_id',$q['register_id']);
    })
    ->orWhere('area_id','IN',  function ($query) use($q) {
        $query->where('parent_id','IN', function ($query) use($q) {
            $query->where('parent_id',$q['area_id']);
        })
        ->where('register_id',$q['register_id']);
    })
    ->where('register_id',$q['register_id']);

But this did the same as the first. My 3rd attempt:

$query
    ->where('area_id', $q['area_id'])
    ->orWhere('area_id','IN',  function ($query) use($q) {
        $query->DB::table('risk_areas')
            ->select(DB::raw('id'))
            ->where('parent_id',$q['area_id'])
            ->where('register_id',$q['register_id']);
    })
    ->orWhere('area_id','IN',  function ($query) use($q) {
        $query->DB::table('risk_areas')
            ->select(DB::raw('id'))
            ->where('parent_id','IN', function ($query) use($q) {
                $query->DB::table('risk_areas')
                    ->select(DB::raw('id'))
                    ->where('parent_id',$q['area_id']);
            })
            ->where('register_id',$q['register_id']);
    })
    ->where('register_id',$q['register_id'])->get();

But this does the same as the first. How can I replicate the sql query?

EDIT:

Each register has its own register_id (this is only used to tighten the search).

Each register contains many risks.

Each risk can only have one risk_area.

I have got the same results each time, whether feeding a raw sql query or using the query builder.

The only time where I got different(and correct) results was when I fed the query into phpmyadmin (hence why I want to replicate the working query in my code).

The variables all have correct values as I have checked using dd().

I think the reason is that my syntax on the query builder is incorrect, which is why I ask how to convert my sql query into the laravel query builder.

EDIT 2:

The raw query outputs all the risks for a specific register (all the risks displayed belong to that register). When I hard code values into the raw query, I get the same result (whatever register_id/area_id combo I put in, I will get all the results for that register as this is the default view for the page.). This makes me think that maybe the raw query isn't being processed properly?

To translate WHERE IN (SELECT ... ) , you need to use whereIn .

Also, trying to use DB::table() inside a subquery won't yield the result you expect.

This:

 .., function ($query) use($q) { $query->DB::table('risk_areas') ... })

Should be:

 .., function ($query) use($q) { $query->from('risk_areas') ... })

The translated query should then, end up like this:

DB::table('risks')
    ->where(function ($query) {
        $query->where('register_id', 29)
              ->where('area_id', 1);
    })
    ->orWhere(function ($query) {
        $query->whereIn('area_id', function ($sQuery) {
                  $sQuery->select('id')
                         ->from('risk_areas')
                         ->where('parent_id', 1);
              })
              ->where('register_id', 29);
    })
    ->orWhere(function ($query) {
        $query->whereIn('area_id', function ($sQuery) {
                  $sQuery->select('id')
                         ->from('risk_areas')
                         ->whereIn('parent_id', function ($sQuery2) {
                             $sQuery2->select('id')
                                     ->from('risk_areas')
                                     ->where('parent_id', 1);
                         });
              })
              ->where('register_id', 29);
    })
    ->get();
   

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM