如何创建(我认为)需要 PostgreSQL 子查询的 Rails 查询?
How to create Rails query that (I think) requires PostgreSQL subquery?
不知道该怎么做,所以标题可能不正确。
每个 User
都有一个字符串类型的字段 country
。
给定一个 user_id 数组,国家/地区元组 用于查询 ,找到所有匹配的记录。每个用户都必须找到自己的国家。
例如,这里是元组数组。
[1, 'us'],
[2, 'mexico'],
[3, 'us']
这将 return User
1 如果它存在并且它的国家是 'us'
.
它也应该 return User
2 如果它存在并且它的国家是 'mexico'
.
查询应该return所有匹配结果。
Rails 4.2
我知道这会在纯 SQL 中起作用:例如
SELECT * FROM user
WHERE (id, country) IN ((1, 'us'), (2, 'mexico'), (3, 'us'))
现在我不知道 Rails 如果它是一个成对列表(每个包含两个元素的列表)将如何处理绑定参数。也许这会奏效。
您可以构造原始 sql 并使用活动记录。像这样:
def self.for_multiple_lp(arr=[])
# Handle case when arr is not in the expected format.
condition = arr.collect{|a| "(user_id = #{a[0]} AND country = #{a[1]})"}.join(" OR ")
where(condition)
end
编辑:改进的解决方案
def self.for_multiple_lp(arr=[])
# Handle case when arr is not in the expected format.
condition = arr.collect{|a| "(user_id = ? AND country = ?)"}.join(" OR ")
where(condition, *(arr.flatten))
end
这应该有效。
class User < ApplicationRecord
def self.query_from_tuples(array_of_tuples)
array_of_tuples.inject(nil) do |scope, (id, country)|
if scope
scope.or(where(id: id, country: country))
else
where(id: id, country: country) # this handles the initial iteration
end
end
end
end
结果查询是:
SELECT "users".* FROM "users"
WHERE (("users"."id" = AND "users"."country" = OR "users"."id" = AND "users"."country" = ) OR "users"."id" = AND "users"."country" = )
LIMIT
您还可以通过以下方式调整 kamakazis WHERE (columns) IN (values)
查询:
class User < ApplicationRecord
def self.query_from_tuples_2(array_of_tuples)
# just a string of (?,?) SQL placeholders for the tuple values
placeholders = Array.new(array_of_tuples.length, '(?,?)').join(',')
# * is the splat operator and turns the tuples (flattened) into
# a list of arguments used to fill the placeholders
self.where("(id, country) IN (#{placeholders})", *array_of_tuples.flatten)
end
end
这导致以下查询不那么冗长:
SELECT "users".* FROM "users"
WHERE ((id, country) IN ((1,'us'),(2,'mexico'),(3,'us'))) LIMIT
如果您在 [id, country] 上有复合索引,性能也会更好。
不知道该怎么做,所以标题可能不正确。
每个 User
都有一个字符串类型的字段 country
。
给定一个 user_id 数组,国家/地区元组 用于查询 ,找到所有匹配的记录。每个用户都必须找到自己的国家。
例如,这里是元组数组。
[1, 'us'],
[2, 'mexico'],
[3, 'us']
这将 return User
1 如果它存在并且它的国家是 'us'
.
它也应该 return User
2 如果它存在并且它的国家是 'mexico'
.
查询应该return所有匹配结果。
Rails 4.2
我知道这会在纯 SQL 中起作用:例如
SELECT * FROM user
WHERE (id, country) IN ((1, 'us'), (2, 'mexico'), (3, 'us'))
现在我不知道 Rails 如果它是一个成对列表(每个包含两个元素的列表)将如何处理绑定参数。也许这会奏效。
您可以构造原始 sql 并使用活动记录。像这样:
def self.for_multiple_lp(arr=[])
# Handle case when arr is not in the expected format.
condition = arr.collect{|a| "(user_id = #{a[0]} AND country = #{a[1]})"}.join(" OR ")
where(condition)
end
编辑:改进的解决方案
def self.for_multiple_lp(arr=[])
# Handle case when arr is not in the expected format.
condition = arr.collect{|a| "(user_id = ? AND country = ?)"}.join(" OR ")
where(condition, *(arr.flatten))
end
这应该有效。
class User < ApplicationRecord
def self.query_from_tuples(array_of_tuples)
array_of_tuples.inject(nil) do |scope, (id, country)|
if scope
scope.or(where(id: id, country: country))
else
where(id: id, country: country) # this handles the initial iteration
end
end
end
end
结果查询是:
SELECT "users".* FROM "users"
WHERE (("users"."id" = AND "users"."country" = OR "users"."id" = AND "users"."country" = ) OR "users"."id" = AND "users"."country" = )
LIMIT
您还可以通过以下方式调整 kamakazis WHERE (columns) IN (values)
查询:
class User < ApplicationRecord
def self.query_from_tuples_2(array_of_tuples)
# just a string of (?,?) SQL placeholders for the tuple values
placeholders = Array.new(array_of_tuples.length, '(?,?)').join(',')
# * is the splat operator and turns the tuples (flattened) into
# a list of arguments used to fill the placeholders
self.where("(id, country) IN (#{placeholders})", *array_of_tuples.flatten)
end
end
这导致以下查询不那么冗长:
SELECT "users".* FROM "users"
WHERE ((id, country) IN ((1,'us'),(2,'mexico'),(3,'us'))) LIMIT
如果您在 [id, country] 上有复合索引,性能也会更好。