Rails / Postgres - 查找具有n个关联行的行

时间:2015-11-10 19:58:10

标签: sql ruby-on-rails postgresql activerecord postgresql-9.1

在我的Rails 4 / Postgres 9.1应用程序中,用户可以标记短语。通过连接表 phrase_tags 标记表关联的词组表格,并在相应的模型中通过 has_many:通过关联。

我希望用户能够搜索具有所有他们指定为输入的标签的短语。例如,找到用"对象"标记的短语。和"颜色"。

我有一个看起来像这样的工作解决方案(在phrase.rb中)。 tags_array是一个字符串数组:

scope :tagged_with_all, -> (tags_array) {
  joins(:tags)
  .where("tags.name in (?)", tags_array)
  .group("phrases.id").having("count(*) = ?", tags_array.count)
}

ActiveRecord转换为:

SELECT "phrases".* FROM "phrases" 
INNER JOIN "phrase_tags" ON "phrase_tags"."phrase_id" = "phrases"."id"   
INNER JOIN "tags" ON "tags"."id" = "phrase_tags"."tag_id" 
WHERE (tags.name in ('objects','colors')) 
GROUP BY phrases.id HAVING count(*) = 1

这很好用,GROUP BY / HAVING只选择那些有多个关联标签等于tags_array长度的短语。

问题在于:当我将此范围与其他具有另一个JOIN的内容组合时,Postgres会抱怨该连接表的主键必须包含在GROUP BY子句中或聚合(参见下面的示例)。有没有其他方法可以使这个工作(可能使用递归子选择?)不使用GROUP BY?

示例错误:在这里,我想获取所有标记的短语,并使用给定语言的翻译加入:

Phrase.joins("LEFT JOIN translations t on t.phrase_id = phrases.id and 
t.language_id = #{lang_id}")
.select("phrases.*, t.id AS translation_id, t.native_text as
translated_text")
.tagged_with_all(tag_items)

生成的SQL:

SELECT phrases.*, t.id AS translation_id, t.native_text as translated_text 
FROM "phrases" INNER JOIN "phrase_tags" 
ON "phrase_tags"."phrase_id" = "phrases"."id" 
INNER JOIN "tags" ON "tags"."id" = "phrase_tags"."tag_id" 
LEFT JOIN translations t on t.phrase_id = phrases.id and t.language_id = 11 
WHERE (tags.name in ('objects','colors')) 
GROUP BY phrases.id HAVING count(*) = 2

例外:

ActiveRecord::StatementInvalid: PG::GroupingError: ERROR:  column "t.id"
must appear in the GROUP BY clause or be used in an aggregate function

0 个答案:

没有答案