使用 Arel (Rails 5) 构建三重 UNION 查询
问题:使用 Arel (Rails 5) 构建三重 UNION 查询 user has_many tasks 我正在尝试创建一个 3 选择 UNION: Task.from("(#{select1.to_sql} UNION #{select2.to_sql} UNION #{select3.to_sql}) AS tasks") 但与阿雷尔。 我可以轻松地将 Arel 用于 UNION 查询进行
·
问题:使用 Arel (Rails 5) 构建三重 UNION 查询
user has_many tasks
我正在尝试创建一个 3 选择 UNION:
Task.from("(#{select1.to_sql} UNION #{select2.to_sql} UNION #{select3.to_sql}) AS tasks")
但与阿雷尔。
我可以轻松地将 Arel 用于 UNION 查询进行 2 次选择:
tasks_t = Task.arel_table
select1 = tasks_t.project('id').where(tasks_t[:id].eq(1)) # SELECT id FROM tasks WHERE tasks.id = 1
select2 = Task.joins(:user).select(:id).where(users: {id: 15}).arel # SELECT "tasks".id FROM "tasks" INNER JOIN "users" ON "users"."id" = "tasks"."user_id" WHERE "users"."id" = 15
union = select1.union(select2) # SELECT * FROM users WHERE users.id = 1 UNION SELECT * FROM users WHERE users.id = 2
union_with_table_alias = tasks_t.create_table_alias(union, tasks_t.name)
Task.from(union_with_table_alias)
# SELECT "tasks".* FROM ( SELECT id FROM "tasks" WHERE "tasks"."id" = 1 UNION SELECT "tasks"."id" FROM "tasks" INNER JOIN "users" ON "users"."id" = "tasks"."user_id" WHERE "users"."id" = $1 ) "tasks" [["id", 15]]
#=> Task::ActiveRecord_Relation [#<Task: id: 1>, #<Task: id: 2>]
如何使用三重联合选择来做到这一点?
select3 = tasks_t.project('id').where(tasks_t[:id].eq(3)) # SELECT id FROM tasks WHERE tasks.id = 3
就像是:
triple_union = select1.union(select2).union(select3)
triple_union_with_table_alias = tasks_t.create_table_alias(triple_union, tasks_t.name)
Task.from(triple_union_with_table_alias)
这应该大致翻译为
Task.from("(#{select1.to_sql} UNION #{select2.to_sql} UNION #{select3.to_sql}) AS tasks")
注意上面的行也失败了:Caused by PG::ProtocolViolation: ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1
总结一下:如何使用Arel
构建一个三重UNION查询?select 1 UNION select 2 UNION select 3
谢谢
Ruby 2.5.3``Rails 5.2.4``Arel 9.0.0
解答
您不能在Arel::Nodes::Union
中调用union
,因为在方法定义中调用了两个对象的ast
。并且union
操作的结果不响应ast
:
def union operation, other = nil
if other
node_class = Nodes.const_get("Union#{operation.to_s.capitalize}")
else
other = operation
node_class = Nodes::Union
end
node_class.new self.ast, other.ast
end
您可以做的是手动调用 Arel::Nodes::Union,将联合的结果作为这些参数中的任何一个传递:
Arel::Nodes::Union.new(Arel::Nodes::Union.new(select1, select2), select3)
更多推荐
已为社区贡献19912条内容
所有评论(0)