Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CTE (WITH queries) in Laravel query builder

In a project, I'm using a Common Table Expression (CTE) in Postgres for a recursive expression on a table. The recursive expression figures out all child rows under a parent.

I'm using the Laravel framework with query builder to write this query. I would like to avoid raw queries. I am looking for a way to chain the CTE in the query builder syntax, but I end up with a raw query (DB::select('raw query here')).

Is there a way that I can chain the CTE part? Like below in pseudo code:

DB::statement('WITH RECURSIVE included_parts(sub_part, part, quantity) AS (  
SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product'
 UNION ALL
  SELECT p.sub_part, p.part, p.quantity
  FROM included_parts pr, parts p
  WHERE p.part = pr.sub_part')
->select('subpart')
->table('included_parts')
->join('bar', 'foo.id', '=', 'bar.foo_id')
->etc etc more query expressions
like image 704
Chris Avatar asked Dec 21 '16 08:12

Chris


People also ask

How do you query a CTE?

The CTE query starts with a “With” and is followed by the Expression Name. We will be using this expression name in our select query to display the result of our CTE Query and be writing our CTE query definition. To view the CTE result we use a Select query with the CTE expression name.

Are CTE materialized?

By using the variable materialize_ctes , common table expressions (CTEs) are materialized when queries with CTEs are run. The materialized results can then be referenced multiple times by the parent query. The CTE queries are cached, which results in optimized performance.


1 Answers

I've created a package for common table expressions: https://github.com/staudenmeir/laravel-cte

$query = 'SELECT sub_part, part, quantity FROM parts [...]';

DB::table('included_parts')
    ->withRecursiveExpression('included_parts', $query, ['sub_part', 'part', 'quantity'])
    ->select('subpart')
    ->join('bar', 'foo.id', '=', 'bar.foo_id')
    ->[...]

You can also provide a query builder instance:

$query = DB::table('parts')
    ->where('part', 'our_product')
    ->unionAll(
        DB::query()->[...]
    )

DB::table('included_parts')
    ->withRecursiveExpression('included_parts', $query, ['sub_part', 'part', 'quantity'])
    ->select('subpart')
    ->join('bar', 'foo.id', '=', 'bar.foo_id')
    ->[...]
like image 136
Jonas Staudenmeir Avatar answered Sep 19 '22 02:09

Jonas Staudenmeir