Create a WHERE (columns) IN (values) clause with Arel?

max*_*max 5 ruby-on-rails arel

Is there a way to programatically create a where clause in Arel where the columns and values are specified separately?

SELECT users.*
WHERE (country, occupation) IN (('dk', 'nurse'), ('ch', 'doctor'), ...
Run Code Online (Sandbox Code Playgroud)

Say the input is a really long list of pairs that we want to match.

I'm am NOT asking how to generate a WHERE AND OR clause which is really simple to do with ActiveRecord.

So far I just have basic string manipulation:

columns = [:country, :occupation]
pairs = [['dk', 'nurse'], ['ch', 'doctor']]
User.where(
  "(#{columns.join(', ')}) IN (#{ pairs.map { '(?, ?)' }.join(', ')})", 
  *pairs
)
Run Code Online (Sandbox Code Playgroud)

Its not just about the length of the query WHERE (columns) IN (values) will also perform much better on Postgres (and others as well) as it can use an index only scan where OR will cause a bitmap scan.

I'm only looking for answers that can demonstrate generating a WHERE (columns) IN (values) query with Arel. Not anything else.

我读过的所有关于 Arel 的文章都开始构建一个专栏:

arel_table[:foo].eq...
Run Code Online (Sandbox Code Playgroud)

我还没有找到任何涉及此案例的文档或文章。

Dav*_*vid 3

这样做的技巧是正确构建分组,然后将它们传递到 Arel In Node,例如:

columns = [:country, :occupation]
pairs = [['dk', 'nurse'], ['ch', 'doctor']]

User.where(
    Arel::Nodes::In.new(
        Arel::Nodes::Grouping.new( columns.map { |column| User.arel_table[column] } ),
        pairs.map { |pair| Arel::Nodes::Grouping.new(
            pair.map { |value| Arel::Nodes.build_quoted(value) } 
        )}
    )
)
Run Code Online (Sandbox Code Playgroud)

上面将生成以下 SQL 语句(对于 MySQL):

“SELECT users.* FROM usersWHERE ( users. country, users. occupation) IN (('dk', '护士'), ('ch', '医生'))”