等效 DBIx::Class 语法?

equivalent DBIx::Class syntax?

我有这个 mysql 来自这个 question 的查询。

SELECT a.*
FROM products a
INNER JOIN product_tags b ON a.product_id = b.product_id
WHERE b.tag_id IN (1,23,54)
GROUP BY a.product_id
HAVING COUNT(1) = 3

我想知道如何将其转换为 DBIx::Class 语法?

来自 DBIx 文档,这是关于联接的内容,但我不确定如何合并它?

定义联接和关系 ^

在 DBIx::Class 中,两个 table 之间的每个关系都需要首先在 table 的 ResultSource 中定义。如果需要双向访问关系(即获取 CD 的所有轨道,并获取轨道的 CD 数据),则需要为两个 tables.

定义它

对于CDs/Tracks的例子,就是写,in MySchema::CD:

  MySchema::CD->has_many('tracks', 'MySchema::Tracks');

在MySchema::Tracks中:

  MySchema::Tracks->belongs_to('cd', 'MySchema::CD', 'CDID');

还有其他几种类型的关系,DBIx::Class::Relationship 中对它们进行了更全面的描述。 使用联接 ^

定义完所有关系后,在实际连接中使用它们就相当简单了。您选择的关系类型,例如has_many,已经表明将执行哪种连接。例如,has_many 生成一个 LEFT JOIN,它将获取左侧的所有行,无论右侧是否有匹配的行(table 被连接到)。您可以在您的关系中强制加入其他类型的连接,请参阅 DBIx::Class::Relationship 文档。

执行搜索或查找操作时,您可以使用 join 属性指定还根据哪些关系优化结果,如下所示:

  $schema->resultset('CD')->search(
    { 'Title' => 'Funky CD',
      'tracks.Name' => { like => 'T%' }
    },
    { join      => 'tracks',
      order_by  => ['tracks.id'],
    }
  );

如果您不认识其中的大部分语法,您可能应该阅读 DBIx::Class::ResultSet 中的 "search" 和 DBIx::Class::ResultSet 中的 "ATTRIBUTES" ,但这里有一个快速分解:

搜索的第一个参数是 WHERE 属性的 hashref,在本例中是对 CD table 中 Title 列的限制,以及对 Tracks [=] 中曲目名称的限制54=],但仅适用于与所选 CD 实际相关的曲目。第二个参数是搜索属性的 hashref,返回的结果将按相关曲目的 id 排序。

因此,首先您要在产品标签上定义一个 rel。

 MySchema::Result::Product->has_many(
    'tags', 'MySchema::Result::ProductTag', 'product_id'
 );

然后根据标签定义产品的相关性:

 MySchema::Result::ProductTag->belongs_to(
    'products', 'MySchema::Result::Product', 'product_id'
 );

如果您顺便使用 Schema::Loader,这些应该已经被推断出来了。 (无耻的插件:上面的DBIx::Class::Candy和DBIx::Class::Helper::Row::RelationshipDWIM会更短更甜)

现在复制您的原始查询:

$schema->resultset('Product')->search({
  tags.tag_id => { -in => [1,23,54] },
}, {
  join => 'tags',
  group_by => 'me.product_id',
  having => { 'count 1' => 3 },
})