简体   繁体   中英

How to convert left join lateral SQL query to Laravel Eloquent query?

I would like to convert this following Postgre SQL query in an Eloquent query:

SELECT ncts_info.nct_id, A.agency_model, ncts_info.indexation_id
FROM ncts_info
LEFT JOIN (
    drug_centers LEFT JOIN LATERAL json_to_recordset(nct_numbers) AS tbl(nct_number text) ON true
) A ON A.nct_number = ncts_info.nct_id

How can I convert this into an Eloquent query?

I managed somehow to partially get the right Laravel query but something is missing:

NctsInfo::leftJoin('drug_centers', function($join) {
   $join->leftJoin(DB::raw('LATERAL json_to_recordset(nct_numbers) AS tbl(nct_number text)'), DB::raw('1'), '=', DB::raw('1'));
   $join->on(DB::raw('dc.nct_number'), '=' ,DB::raw('ncts_info.nct_id'));
})
->whereNotNull("nct_numbers")->get();

But according to my expected sql query:

SELECT ncts_info.nct_id, A.agency_model, ncts_info.indexation_id FROM ncts_info
LEFT JOIN (
    drug_centers LEFT JOIN LATERAL json_to_recordset(nct_numbers) AS tbl(nct_number text) ON true
) A ON A.nct_number = ncts_info.nct_id

I need to "alias" my first left join with "A" to get my nct_number field.

Anyone knows how to solved this?

Thank you for your help

The best way I've found to do this is to define a subquery first. From the laravel docs:

Posts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
               ->where('is_published', true)
               ->groupBy('user_id');

$users = DB::table('users')
    ->joinLeftSub($latestPosts, 'latest_posts', function ($join) {
        $join->on('users.id', '=', 'latest_posts.user_id');
    })->get();

In your second response here, you mention that you need to reference the join as A - you don't need to. You can change A to drug_centers in Laravel as it will be aliased as the table name.

FWIW, I solved the original question by creating a custom Macro for the Builder class that will let you do a join prefixed with the LATERAL keyword:

Builder::macro('joinSubLateral', function ($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false) {
    [$query, $bindings] = $this->createSub($query);

    $expression = 'LATERAL ('.$query.') as '.$this->grammar->wrapTable($as);

    $this->addBinding($bindings, 'join');

    return $this->join(new Expression($expression), $first, $operator, $second, $type, $where);
});

Put this in the register method of a Service Provider and you're all set!

Keep in mind it doesn't check for database compatibility.

You can use DB like that in laravel

$data = DB::table('ncts_info')
->leftJoin('drug_centers', 'drug_centers.foreign_key', 'ncts_info.id')
->select('ncts_info.nct_id','A.agency_model','ncts_info.indexation_id')
->get();

This would produce the following query:

SELECT "ncts_info"."nct_id", "A"."agency_model", "ncts_info"."indexation_id"
FROM "ncts_info"
LEFT JOIN "drug_centers" ON "drug_centers"."foreign_key" = "ncts_info"."id";

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