如何在SELECT部分​​的DBIx :: Class中使用子查询?

时间:2018-07-04 20:32:00

标签: mysql sql perl subquery dbix-class

请帮助在DBIx::Class中编写此MySQL查询(以获取有关如何在DBIx::Class中使用子查询的示例):

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

(我知道可以用JOIN将其重写为GROUP BY,但是我想要子查询(例如,可以动手操作)。

DBIx::Class文档对WHERE子句中的子查询的使用进行了广泛的审查,但是我没有在SELECT字段列表中找到如何使用子查询的方法(如上例所示)。

2 个答案:

答案 0 :(得分:3)

您在正确的轨道上。 as_query是您所需要的。但是,您还需要第二个hashref中的columns option。确保在子查询上使用count_rs,这会翻转内部开关以生成其中包含COUNT(*)的结果集。

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;

结果查询如下所示:

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

如您所见,我们通过子查询选择的值在SQL中未被称为c,但在对象数据中被称为c

use DDP;
p $obj;

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

您可以使用行对象上的get_column访问它。

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

答案 1 :(得分:0)

对于prefetch,如果要选择子查询结果,则必须命名子查询,否则将收到错误消息(请参见simbabque的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 /],
});

尽管如果您想使用子查询作为过滤器,则无需命名即可使用

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