0

这必须是rails中的基本内容,但我不知道该怎么做。

我想根据他们说的语言过滤参与者。人们可以说多种语言,并且语言以一对多的关系存储在他们自己的表中。

现在我的搜索看起来很笨拙,似乎不起作用:

  if @cvsearch.language.present? == true and @cvsearch.language != 0
    @p = @p.joins(:languages).where('languages.name = ?', @cvsearch.language)  
  else
    @cvsearch.language = 0
  end

  if @cvsearch.language1.present? == true and @cvsearch.language1 != 0
    @p = @p.joins(:languages).where('languages.name = ?', @cvsearch.language1)  
  end

  if @cvsearch.language2.present? == true and @cvsearch.language2 != 0
    @p = @p.joins(:languages).where('languages.name = ?', @cvsearch.language2)  
  end

  if @cvsearch.language3.present? == true and @cvsearch.language3 != 0
    @p = @p.joins(:languages).where('languages.name = ?', @cvsearch.language3)  
  end

生成的 SQL,略微缩短:

SELECT COUNT(*) FROM "participants" INNER JOIN "languages" ON "languages"."participant_id" = "participants"."id" WHERE (participants.id >= 2) AND (languages.name = 11) AND (languages.name = 10)[0m

获得一个具体的解决方案会很棒,但更好的是一个关于我可以在哪里阅读的指针——我缺少什么关键词来描述这个问题?

所以这是我现在使用的解决方案:

  if @cvsearch.language1.present? == true and @cvsearch.language1 != 0
    safe_lang = ActiveRecord::Base::sanitize(@cvsearch.language1)
    qry = "INNER JOIN languages l1 ON l1.participant_id = participants.id AND l1.name = " + safe_lang.to_s
    @p = @p.joins(qry)
  end

效果很好,只需要获得一些关于这种方法安全性的反馈。

4

1 回答 1

1

我不确定可以参考您的一般参考,但这是基本的 SQL 内容。基本上,JOIN首先执行 产生许多行,然后WHERE应用 过滤行。这里的概念错误是认为该WHERE子句将以某种方式适用于所有匹配的语言,但它不起作用,结果的每一行都被孤立地考虑,因此子句 like(languages.name = 11) AND (languages.name = 10)永远不会返回任何内容,因为语言.name 在每一行中只有一个值。构造的查询只能用于OR子句,因此您可以说类似WHERE (languages.name = 11) OR (languages.name = 12).

为了过滤参与者,您需要为每种语言加入一个参与者,因此您需要以下内容:

SELECT COUNT(*) FROM participants
INNER JOIN languages l1 ON l1.participant_id = participants.id AND (languages.name = 10)
INNER JOIN languages l2 ON l2.participant_id = participants.id AND (languages.name = 11)
WHERE participants.id >= 2

副手我不确定在 ActiveRecord 中执行此操作的最简单方法,这不是一个超级常见的查询。您的一般结构应该可以工作,但类似于:

if @cvsearch.language1.present? == true and @cvsearch.language1 != 0
  safe_language = ActiveRecord::Base.sanitize(@cvssearch.language1)
  join_clause   = "INNER JOIN languages l1 ON l1.participant_id = participants.id AND language.name = #{safe_language}"
  @p = @p.joins(join_clause)
end
于 2013-06-04T21:27:27.447 回答