简体   繁体   中英

How do I use a sub query in the SELECT part with DBIx::Class?

Please help to write this MySQL query in DBIx::Class (to have an example on how to use subqueries in DBIx::Class ):

SELECT x, (SELECT COUNT(*) FROM t2 WHERE t2.y=x) AS c FROM t1 WHERE t1.z=123

(I know that it can be rewritten as JOIN with GROUP BY , but I want namely subquery (for an example to get my hands on).)

DBIx::Class docs give extensive review of using subqueries in WHERE clause but I didn't find how to use a subquery in the SELECT fields list (as in the above example).

You were on the right track. The as_query is what you need. But you also need the columns option in the second hashref. Make sure you use count_rs on the sub query, which flips the internal switch to produce a resultset with COUNT(*) in it.

my $obj = ResultSet('TableOne')->search(
    { 
         z => 123,
    },
    {
        columns => [
            'x',
            {
                c => ResultSet('TableTwo')->search(
                    {
                        'y' => {
                            -ident => 'me.x',
                        },
                    },
                    {
                        alias => 'sub_query', # this name is arbitrary
                    },
                )->count_rs->as_query,
            },
        ],
    }
)->first;

The resulting query will look something like this:

SELECT me.x, ( 
    SELECT COUNT( * ) 
      FROM table_two sub_query
    WHERE y = me.x
   )
  FROM table_one me
WHERE me.z = 123

As you can see, the value that we selected via the sub query is not called c in the SQL, but it is called c in the object's data.

use DDP;
p $obj;

DB::Result::TableOne  {
    # ...
    internals: {
        _column_data     {
            x        "foo",
            c        "bar"
        },
        _in_storage      1,
        _result_source   DBIx::Class::ResultSource::Table
    }
}

You can access it with get_column on the row object.

say $obj->get_column('c');
# bar

In case of prefetch and you want select subquery result you must name your subqueries, otherwise you will get the error (see comments under simbabque's answer )

my $partial =  $c->model( 'ServicePackageSet' )->search([
    { service_type_id_covered => { -ident => 'me.id' } },
    { service_type_id_surplus => { -ident => 'me.id' } },
],{ select => \1 });

my $pricelist =  $c->model( 'ServiceTree' )->search({
},{
    '+select' => { exists => $partial->as_query },
    '+as' => [ 'partial' ],
    prefetch => [qw/ Price Package /],
    order_by => [qw/ Package.short_name name /],
});

though if you want to use subquery as filter it will work without naming:

my $pricelist =  $c->model( 'ServiceTree' )->search({
    -not_exists => $partial->as_query
},{
    prefetch => [qw/ Price Package /],
    order_by => [qw/ Package.short_name name /],
});

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