Rails 不查询整个 Where 子句
Rails Not query on entire Where clause
是否有直接的方法使用 ActiveRecord/ARel 否定整个 where
表达式?似乎 where.not()
,当给定参数的散列时,会单独否定每个表达式,而不是用单个 SQL NOT
.
来否定整个事物
Rails 例子
Thing.where.not(attribute1: [1,2], attribute2: [3,4], attribute3: [5,6])
会产生 SQL:
select * from things where attribute1 NOT IN (1,2) AND attribute2 NOT IN (3,4) AND attribute3 NOT IN (5,6)
但这不是我想要做的。我想用一个 NOT
.
否定整个 where 子句
select * from things where NOT(attribute1 IN (1,2) AND attribute2 IN (3,4) AND attribute3 IN (5,6))
在布尔符号中,Rails 似乎倾向于否定 WHERE 子句的每个组成部分,如下所示:
!(a) && !(b) && !(c)
但我想否定整个表达式:
! [ (a) && (b) && (c) ]
使用 DeMorgan 定律,我可以将查询写成 !a || !b || !c
,但这会导致一些相当长且难看的代码(Rails 5 和 or
的代码不那么长,但是还是丑)。我希望使用 ActiveRecord 或 ARel 时缺少一些语法糖?
背景故事
我正在编写 Ransack Equality Scope(例如 _eq)来搜索条件及其相反条件。
scope :can_find_things_eq, ->(boolean = true) {
case boolean
when true, 'true'
where(conditions_for_things)
when false, 'false'
where.not(conditions_for_things)
end
}
def self.ransackable_scopes(_auth_object = nil)
%i[can_find_things_eq]
end
如果我使用我上面的 Rails 5 建议和我开始的例子,我可以让我的否定查询工作......但是代码又长又难看。
where.not(attribute1: [1,2]).or(where.not(attribute2:
[3,4)).or(where.not(attribute3: [5,6))
链接 Ors 和 WhereNots 可行,但可读性不佳。除了必须使用 DeMorgan 定律来否定它 manually/logically 之外,还有更好的方法来否定这个 where
吗?
谢谢!
您可以使用 Arel 生成所需的结果,如下所示:
table = Thing.arel_table
clause = Arel::Nodes::Not.new(
table[:attribute1].in([1,2]).and(
table[:attribute2].in([2,3]).and(
table[:attribute3].in([5,6])
)))
Thing.where(clause)
或者
Thing.where.not(
table[:attribute1].in([1,2]).and(
table[:attribute2].in([2,3]).and(
table[:attribute3].in([5,6])
)))
如果你正在使用Rails7,你可以使用invert_where。这将完全按照您的需要形成查询
! [ (a) && (b) && (c) ]
是否有直接的方法使用 ActiveRecord/ARel 否定整个 where
表达式?似乎 where.not()
,当给定参数的散列时,会单独否定每个表达式,而不是用单个 SQL NOT
.
Rails 例子
Thing.where.not(attribute1: [1,2], attribute2: [3,4], attribute3: [5,6])
会产生 SQL:
select * from things where attribute1 NOT IN (1,2) AND attribute2 NOT IN (3,4) AND attribute3 NOT IN (5,6)
但这不是我想要做的。我想用一个 NOT
.
select * from things where NOT(attribute1 IN (1,2) AND attribute2 IN (3,4) AND attribute3 IN (5,6))
在布尔符号中,Rails 似乎倾向于否定 WHERE 子句的每个组成部分,如下所示:
!(a) && !(b) && !(c)
但我想否定整个表达式:
! [ (a) && (b) && (c) ]
使用 DeMorgan 定律,我可以将查询写成 !a || !b || !c
,但这会导致一些相当长且难看的代码(Rails 5 和 or
的代码不那么长,但是还是丑)。我希望使用 ActiveRecord 或 ARel 时缺少一些语法糖?
背景故事
我正在编写 Ransack Equality Scope(例如 _eq)来搜索条件及其相反条件。
scope :can_find_things_eq, ->(boolean = true) {
case boolean
when true, 'true'
where(conditions_for_things)
when false, 'false'
where.not(conditions_for_things)
end
}
def self.ransackable_scopes(_auth_object = nil)
%i[can_find_things_eq]
end
如果我使用我上面的 Rails 5 建议和我开始的例子,我可以让我的否定查询工作......但是代码又长又难看。
where.not(attribute1: [1,2]).or(where.not(attribute2:
[3,4)).or(where.not(attribute3: [5,6))
链接 Ors 和 WhereNots 可行,但可读性不佳。除了必须使用 DeMorgan 定律来否定它 manually/logically 之外,还有更好的方法来否定这个 where
吗?
谢谢!
您可以使用 Arel 生成所需的结果,如下所示:
table = Thing.arel_table
clause = Arel::Nodes::Not.new(
table[:attribute1].in([1,2]).and(
table[:attribute2].in([2,3]).and(
table[:attribute3].in([5,6])
)))
Thing.where(clause)
或者
Thing.where.not(
table[:attribute1].in([1,2]).and(
table[:attribute2].in([2,3]).and(
table[:attribute3].in([5,6])
)))
如果你正在使用Rails7,你可以使用invert_where。这将完全按照您的需要形成查询
! [ (a) && (b) && (c) ]