使用Arel构建三重UNION查询(Rails 5)

问题描述 投票:1回答:1

user has_many tasks

我正在尝试创建3选择UNION:

Task.from("(#{select1.to_sql} UNION #{select2.to_sql} UNION #{select3.to_sql}) AS tasks")

但是有Arel。

我可以轻松地对2个选择使用Arel进行UNION查询:

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.3Rails 5.2.4Arel 9.0.0

ruby-on-rails ruby-on-rails-5 arel
1个回答
0
投票

您不能在union中调用Arel::Nodes::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)
© www.soinside.com 2019 - 2024. All rights reserved.