1

给定两个表:(显示关键问题的大大简化/简化的示例)

app_data表示可以订阅的应用程序

id   app_name
 1   apple
 2   berry
 3   cherry

app_sub将电子邮件地址映射到应用程序

id   email
 1   alex
 2   bob
 2   coby

我想从单用户的角度生成一个表,显示当前用户订阅了哪些应用程序,而不是。

例如,从亚历克斯的角度来看,我想得到:

期望表

id    app_name    is_subscribed
 1    apple       true
 2    berry       false
 3    cherry      false

以下纯 SQL 查询似乎没问题:

select id, app_name, email
  from app_data left join ( select *
                              from app_sub
                             where email='alex'
                          ) as subquery
                          on app_name.id=app_data.id;

但是,我很难让它在 dbix-class 中工作。

或者,我尝试像这样消除子查询:

$app_data_resultset->search( { -or => [ { email => 'alex' },
                                        { email => undef },
                                      ],
                             },
                             { select => [ qw{ me.id
                                               me.app_name
                                               app_sub.email
                                             },
                                         ],
                               as => [ qw{ id
                                           app_name
                                           email
                                         },
                                     ],
                               join => 'app_sub',
                           );

但是,这(现在可以预期)会导致以下结果(在将 0 和 null 都视为 false 之后):

坏表

id    app_name    is_subscribed
 1    apple       true
 3    cherry      false

由于 'bob' 和 'coby' 订阅了 id 2,因此 where 子句完全消除了第二个 id。

任何帮助将不胜感激!

4

2 回答 2

5

我自己做了这件事而没有使用 100% 任意 SQL,因为 IMO 有点糟糕。我所做的是将所说的子查询插入到一些原始 SQL 中,然后使用来生成更多查询。所以这是我的例子(来自https://github.com/frioux/drinkup/blob/master/lib/DU/Schema/ResultSet/Drink.pm#L164):

sub ineq {
   my ($self, $ingredient_rs, $min, $max) = @_;

   my $ingredients_on_hand = $ingredient_rs
      ->search(undef, {
         join => { kind_of => 'links_to_drink_ingredients' },
         columns => {
            drink_id => 'links_to_drink_ingredients.drink_id',
            ingredient_count => { count => '*', -as => 'ingredient_count' },
         },
         group_by => 'links_to_drink_ingredients.drink_id',
      })->as_query;


   my $required_ingredients = $self->result_source->schema->resultset('Drink_Ingredient')
      ->search(undef, {
         columns => {
            drink_id => 'me.drink_id',
            ingredient_count => { count => '*', -as => 'ingredient_count' },
         },
         group_by => 'me.drink_id',
      })->as_query;

   my ($ioh_sql, @ioh_bind) = @{$$ingredients_on_hand};
   my ($ri_sql, @ri_bind) = @{$$required_ingredients};

   my $creation = \[
   <<"SQL",
      SELECT di.drink_id FROM (
         $ri_sql di,
         $ioh_sql ii
      )
      WHERE di.drink_id = ii.drink_id AND
            di.ingredient_count >= ii.ingredient_count + ? AND
            di.ingredient_count <= ii.ingredient_count + ?
SQL
   @ri_bind, @ioh_bind, [{ sqlt_datatype => 'int' } => $min], [{ sqlt_datatype => 'int' } => $max] ];

   $self->search({ 'me.id' => { -in => $creation } });
}

如果我在某个时候有时间,我会将其归结为一个更易于理解的示例,但重点是我使用 DBIx::Class 生成硬查询并手动将它们粉碎在一个小地方,然后将其包装起来在子查询中,这样我就可以使用普通的 DBIx::Class 结果集方法进行更多搜索。

于 2012-10-15T20:56:00.947 回答
-1

文森特,我现在正在尝试自己加入子查询。到目前为止,我找不到任何人成功。

另一种方法是使用 $c->model('blah')->storage->dbh->prepare("query") 或 DBIx 类的“通过自定义 ResultSource 的任意 SQL”部分在普通 SQL 中执行此操作Cookbook,这似乎也是一种合理的方式。

于 2011-10-16T22:07:56.370 回答