简体   繁体   English

如何使用DBIx :: Class进行子选择?

[英]How to Subselect with DBIx::Class?

I'm starting with DBIx::Class and i have a subselect that wanted to be in DBIx::Class, but i'm getting confused and can't build the code. 我从DBIx :: Class开始,我有一个想要在DBIx :: Class中的子选择,但我感到困惑,无法构建代码。

My MySQL select is this one: 我的MySQL选择是这个:

Select name from tblCategory where id = (
    Select id from tblCategory where id = (
         Select id from tblRadio where name = "RFM"
    )
);

I read that DBIx::Class don't support subselect; 我读到DBIx :: Class不支持subselect; is that true? 真的吗? If so, what do you do in situations like this? 如果是这样,你在这样的情况下做了什么?

According to the DBIx::Class::Manual::Cookbook there is a new Subquery feature: 根据DBIx::Class::Manual::Cookbook有一个新的子查询功能:

my $inside_rs = $schema->resultset('Radio')->search({ name => 'RFM' });

my $rs = $schema->resultset('Category')->search({
    id => { '=' => $inside_rs->get_column('id')->as_query },
});

It is marked EXPERIMENTAL so YMMV. 它标记为实验所以YMMV。

However also note that SQL::Abstract which DBIx::Class uses when building its queries does have a new subquery feature using -nest. 但是请注意, DBIx::Class在构建查询时使用的SQL::Abstract确实有一个使用-nest的新子查询功能。

Couldn't this be represented as a join? 这不能表示为连接吗?

my $rs = $schema->resultset('Category')->search(
    {   
       'Radio.name' => 'RFM' 
    },
    {   
        'join' => 'Radio'
    }   
);

This assumes you have a relationship in Category named 'Radio'. 这假设您在名为“Radio”的类别中有关系。 If you don't, there's plenty of documentation to help you setup relationships and learn how to perform joins . 如果不这样做,那么有大量文档可以帮助您设置关系并学习如何执行连接

As for subqueries, the cookbook for the most recent version says they are supported , but experimental . 至于子查询,最新版本的食谱说它们是受支持的 ,但是是实验性的

Well, you can always supply a scalar reference to insert literal SQL when you're using DBIC's search() method. 好吧,当你使用DBIC的search()方法时,你总是可以提供一个标量引用来插入文字SQL。 For example: 例如:

my $rs = $schema->resultset('Category')->search({ 
              id => \"(Select id from tblRadio where name = 'RFM')" 
});

That's what I've had to do in the past when I needed more expressiveness than DBIC supported out-of-the-box. 这就是我过去需要做的事情,当我需要比DBIC支持开箱即用更具表现力时。 I don't know, though, whether that's the "right" thing to do in this case. 但我不知道,在这种情况下,这是否是“正确”的事情。

after some fight with DBIC i win in the end :P (YEAH!) 经过与DBIC的一场战斗,我最终获胜:P (YEAH!)

Had to rewrite some stuff, and had to forget the subselects and done the relationships well. 不得不重写一些东西,不得不忘记子选择并完成关系。

I know that this code don't represent the inicial question, but if i had to rewrite all again, i'm showing you the other part of my "project", where i had again other dificulties. 我知道这段代码并不代表真正的问题,但如果我不得不重写所有内容,我会告诉你我的“项目”的另一部分,我还有其他的困难。

Next is what i've done: 接下来是我做的:

DBIx::Class Schema DBIx ::类架构

package DB::Esquema::Passwords;

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components("Core");
__PACKAGE__->table("Passwords");
__PACKAGE__->add_columns(
  "pswd",
  { data_type => "INT", default_value => undef, is_nullable => 0, size => 11 },
  "password",
  {
    data_type => "VARCHAR",
    default_value => undef,
    is_nullable => 1,
    size => 20,
  },
  "utilizadorid",
  { data_type => "INT", default_value => undef, is_nullable => 1, size => 11 },
);
__PACKAGE__->set_primary_key("pswd");
__PACKAGE__->belongs_to('utilizadorid' => 'DB::Esquema::Utilizadores');
#belongs_to is not autogenerated, done by hand

Has a relationship with Utilizadores (users) 与Utilizadores(用户)有关系

package DB::Esquema::Utilizadores;

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components("Core");
__PACKAGE__->table("Utilizadores");
__PACKAGE__->add_columns(
  "utilizador",
  { data_type => "INT", default_value => undef, is_nullable => 0, size => 11 },
  "nome",
  {
    data_type => "VARCHAR",
    default_value => undef,
    is_nullable => 1,
    size => 20,
  },
  "mail",
  {
    data_type => "VARCHAR",
    default_value => undef,
    is_nullable => 1,
    size => 30,
  },
);
__PACKAGE__->set_primary_key("utilizador");
__PACKAGE__->has_one('utilizador' => 'DB::Esquema::Passwords', 'utilizadorid');

NEXT (the script to make it work) NEXT(使其工作的脚本)

#!/usr/bin/perl -w

use strict;
use diagnostics; #was important to understand
use lib '/var/www/projectox/lib'; #is where the schema is
use DB::Esquema; #use the Schema

system('clear'); # clear the screen

my $esquema = DB::Esquema->connect("dbi:mysql:dbname=dbswiak","root","");
    $esquema->storage->debug(1);

    #HAD TO USE PREFETCH
    my $resultado = $esquema->resultset('Utilizadores')->search(
    undef,{
         prefetch => { 'utilizador' => 'utilizadorid' }
      }
    )->next();

The Result: 结果:

    SELECT me.utilizador, me.nome, me.mail, utilizador.pswd, 
utilizador.password, utilizador.utilizadorid, utilizadorid.utilizador, utilizadorid.nome, utilizadorid.mail 
FROM Utilizadores me JOIN Passwords utilizador 
ON utilizador.utilizadorid = me.utilizador 
JOIN Utilizadores utilizadorid ON utilizadorid.utilizador = utilizador.utilizadorid: 

Wasn't what i really wanted, but is the nearest, the goal is to select only the columns i want... maybe i will reach that goal 不是我真正想要的,但它是最近的,目标是只选择我想要的列...也许我会达到那个目标

Subselects are experimental feature now and useful if you need to be able to allow them at compile time. 子选择现在是实验性功能,如果您需要能够在编译时允许它们,则它们非常有用。 However I find the following to be a good approach: 但是我发现以下是一个很好的方法:

  1. most subselects can be done as a (faster) join - so use a join where you can 大多数子选择可以作为(更快)连接完成 - 所以尽可能使用连接
  2. failing that, create a view in the database and a schema class for the view. 如果失败了,请在数据库中创建一个视图,并为视图创建一个模式类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM