【问题标题】:How do I use a sub query in the SELECT part with DBIx::Class?如何在带有 DBIx::Class 的 SELECT 部分中使用子查询?
【发布时间】:2018-12-13 07:03:41
【问题描述】:

请帮助在DBIx::Class 中编写这个 MySQL 查询(在DBIx::Class 中有一个如何使用子查询的示例):

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

(我知道它可以用GROUP BY 重写为JOIN,但我想要的是子查询(举个例子)。)

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

【问题讨论】:

  • 你试过什么?你有什么问题?请向我们展示您的代码。
  • @DaveCross 问题是我不知道它的语法。
  • 谢谢@porton,我昨天整天都在寻找get_columns 语法,由于您的问题,由于某种原因,今天才找到它。求自己帮助别人✊

标签: mysql sql perl subquery dbix-class


【解决方案1】:

你在正确的轨道上。 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

【讨论】:

  • 嗨。请您扩展您的示例以使用 EXISTS 关键字,例如SELECT exists( select .... )
  • @EugenKonkov 你的意思是 DBIC 代码?有趣的。我想那只是c => { '-exists' => ResultSet('foo')->count_rs->as_query }
  • 我找到了。我应该使用+select and +as 来命名值为select 语句的列。否则会有错误。 rt.cpan.org/Ticket/Display.html?id=126958
  • @EugenKonkov 我同意你的票是有道理的,但我不明白它与你之前关于 EXISTS 关键字的评论有什么关系。
  • 我正在寻找使用存在关键字进行子查询的解决方案。问题在于,如果没有 +as 属性(当还需要预取时),您的猜测将不起作用,因此我问了一个示例。
【解决方案2】:

如果是prefetch,并且你想选择子查询结果,你必须命名你的子查询,否则你会得到错误(参见simbabque的answer下的cmets)

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 /],
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 2020-06-30
    相关资源
    最近更新 更多