Rails - 如何将不兼容的语句与 OR 组合 (Rails 5)
Rails - how to combine incompatible statements with OR (Rails 5)
有项目模型和付款模型:
class Project < ApplicationRecord
has_many :payments
end
class Payment < ApplicationRecord
belongs_to :project
end
我很容易将列查询与 or
或 and
.
组合起来
Project.where(projects[:created_at].gt(6.months.ago).or(projects[:updated_at].gt(1.month.ago)))
使用 Arel 的原因是确切的列、运算符和值来自用户,而 Arel 运算符与用户可以匹配的非常好select。
但是,如果我想将它与来自另一个关联 table 的数据结合起来,那么我就不知道该怎么做。 ActiverRecord 要求 OR
在结构上兼容,所以我不能这样做:
Project.where(projects[:created_at].gt(6.months.ago)).or(Project.joins(:payments))
像这样:
Project.where(projects[:created_at].gt(6.months.ago).or(projects.join(payments).on(projects[:id].eq(payments[:project_id]))))
引发异常:ActiveRecord::StatementInvalid:PG::SyntaxError:错误:子查询必须 return 只有一列。
我能够做到的一种方式是这样的:
Project.where(projects[:created_at].gt(6.months.ago)).or(Project.where(id: Project.joins(:payments).select(:id)))
生成了 SQL
SELECT "projects".* FROM "projects" WHERE (("projects"."created_at" > '2019-08-19 09:11:22.064298') OR "projects"."id" IN (SELECT "projects"."id" FROM "projects" INNER JOIN "payments" ON "payments"."project_id" = "projects"."id"))
这是最好的方法还是有更好的方法?请可能有 10 多个这样的子句组合在一起,涉及多个 tables,在所有可能的 tables 上使用 include
以使所有单个子句兼容可能太昂贵了。
是否有任何原因导致您无法在不同条件下保持连接一致?例如在 Rails 5+ 你可以这样写:
Project.where(some_field: '12').joins(:payments)
.or(
Project.where(payments: {id: '1'}).joins(:payments)
)
这会生成 SQL 比如:
SELECT projects.* FROM projects
INNER JOIN payments ON (payments.project_id = project.id)
WHERE projects.some_field = 12 OR payments.id = 1
注:
使用 OP 中结构不兼容的示例,您可以简单地向第一个条件添加连接以使其兼容:
Project.where(projects[:created_at].gt(6.months.ago)).joins(:payments).or(Project.joins(:payments))
有项目模型和付款模型:
class Project < ApplicationRecord
has_many :payments
end
class Payment < ApplicationRecord
belongs_to :project
end
我很容易将列查询与 or
或 and
.
Project.where(projects[:created_at].gt(6.months.ago).or(projects[:updated_at].gt(1.month.ago)))
使用 Arel 的原因是确切的列、运算符和值来自用户,而 Arel 运算符与用户可以匹配的非常好select。
但是,如果我想将它与来自另一个关联 table 的数据结合起来,那么我就不知道该怎么做。 ActiverRecord 要求 OR
在结构上兼容,所以我不能这样做:
Project.where(projects[:created_at].gt(6.months.ago)).or(Project.joins(:payments))
像这样:
Project.where(projects[:created_at].gt(6.months.ago).or(projects.join(payments).on(projects[:id].eq(payments[:project_id]))))
引发异常:ActiveRecord::StatementInvalid:PG::SyntaxError:错误:子查询必须 return 只有一列。
我能够做到的一种方式是这样的:
Project.where(projects[:created_at].gt(6.months.ago)).or(Project.where(id: Project.joins(:payments).select(:id)))
生成了 SQL
SELECT "projects".* FROM "projects" WHERE (("projects"."created_at" > '2019-08-19 09:11:22.064298') OR "projects"."id" IN (SELECT "projects"."id" FROM "projects" INNER JOIN "payments" ON "payments"."project_id" = "projects"."id"))
这是最好的方法还是有更好的方法?请可能有 10 多个这样的子句组合在一起,涉及多个 tables,在所有可能的 tables 上使用 include
以使所有单个子句兼容可能太昂贵了。
是否有任何原因导致您无法在不同条件下保持连接一致?例如在 Rails 5+ 你可以这样写:
Project.where(some_field: '12').joins(:payments)
.or(
Project.where(payments: {id: '1'}).joins(:payments)
)
这会生成 SQL 比如:
SELECT projects.* FROM projects
INNER JOIN payments ON (payments.project_id = project.id)
WHERE projects.some_field = 12 OR payments.id = 1
注:
使用 OP 中结构不兼容的示例,您可以简单地向第一个条件添加连接以使其兼容:
Project.where(projects[:created_at].gt(6.months.ago)).joins(:payments).or(Project.joins(:payments))