有没有办法反转 ActiveRecord::Relation 查询?

发布于 2024-10-22 01:30:17 字数 372 浏览 1 评论 0原文

假设我们有以下内容:

irb> Post.where(:hidden => true).to_sql
=> "SELECT `posts`.* FROM `posts` WHERE posts.hidden = 1"

我们能否以某种方式从中获得反向 SQL 查询?

我正在寻找的内容可能应该如下所示:

irb> Post.where(:hidden => true).invert.to_sql
=> "SELECT `posts`.* FROM `posts` WHERE NOT (posts.hidden = 1)"

Let's say we have the following:

irb> Post.where(:hidden => true).to_sql
=> "SELECT `posts`.* FROM `posts` WHERE posts.hidden = 1"

Could we somehow get an inverted SQL query out of it?

What I am looking for, should probably look like this:

irb> Post.where(:hidden => true).invert.to_sql
=> "SELECT `posts`.* FROM `posts` WHERE NOT (posts.hidden = 1)"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

羁客 2024-10-29 01:30:17

使用不同的语法,是的。例子:

posts = Post.scoped.table # or Arel::Table.new("posts")
posts.where(posts[:hidden].eq(true).not).to_sql
# => SELECT  FROM `posts` WHERE NOT ((`posts`.`hidden` = 1))

With a different syntax, yes. Example:

posts = Post.scoped.table # or Arel::Table.new("posts")
posts.where(posts[:hidden].eq(true).not).to_sql
# => SELECT  FROM `posts` WHERE NOT ((`posts`.`hidden` = 1))
辞旧 2024-10-29 01:30:17

在 Rails 4 中,有用于此目的的 not 后缀:

Post.where.not(hidden: true).to_sql
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1

在 Rails 3 中,您可以使用 squeel gem< /a>.它提供了许多有用的功能。用它你可以写:

Post.where{ hidden != true }.to_sql
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1

In rails 4 there is not suffix for this purpose:

Post.where.not(hidden: true).to_sql
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1

In rails 3 you can use squeel gem. It gives many usefull features. And with it you can write:

Post.where{ hidden != true }.to_sql
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1
成熟稳重的好男人 2024-10-29 01:30:17

我们可以进一步采用 Zabba 的回答通过将反向查询传递回 ActiveRecord:

table = Post.arel_table
query = table[:hidden].eq(true).not # the inverted query, still ARel
Post.where(query) # plug it back into ActiveRecord

这将返回 ActiveRecord 对象,正如您通常所期望的那样。

We can take Zabba's answer further by passing the inverted query back into ActiveRecord:

table = Post.arel_table
query = table[:hidden].eq(true).not # the inverted query, still ARel
Post.where(query) # plug it back into ActiveRecord

This will return ActiveRecord objects, as you would normally expect.

乖乖公主 2024-10-29 01:30:17

invert_where (Rails 7+)

从 Rails 7 开始,有一个新的 invert_where 方法。

根据文档,它:

允许您反转整个 where 子句,而不是手动应用条件。

class User
  scope :active, -> { where(accepted: true, locked: false) }
end

User.where(accepted: true)
# WHERE `accepted` = 1

User.where(accepted: true).invert_where
# WHERE `accepted` != 1

User.active
# WHERE `accepted` = 1 AND `locked` = 0

User.active.invert_where
# WHERE NOT (`accepted` = 1 AND `locked` = 0)

要小心,因为这会反转 invert_where 调用之前的所有条件。

class User
  scope :active, -> { where(accepted: true, locked: false) }
  scope :inactive, -> { active.invert_where } # Do not attempt it
end

# It also inverts `where(role: 'admin')` unexpectedly.
User.where(role: 'admin').inactive
# WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)

来源:

invert_where (Rails 7+)

Starting from Rails 7, there is a new invert_where method.

According to the docs, it:

Allows you to invert an entire where clause instead of manually applying conditions.

class User
  scope :active, -> { where(accepted: true, locked: false) }
end

User.where(accepted: true)
# WHERE `accepted` = 1

User.where(accepted: true).invert_where
# WHERE `accepted` != 1

User.active
# WHERE `accepted` = 1 AND `locked` = 0

User.active.invert_where
# WHERE NOT (`accepted` = 1 AND `locked` = 0)

Be careful because this inverts all conditions before invert_where call.

class User
  scope :active, -> { where(accepted: true, locked: false) }
  scope :inactive, -> { active.invert_where } # Do not attempt it
end

# It also inverts `where(role: 'admin')` unexpectedly.
User.where(role: 'admin').inactive
# WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)

Sources:

纸伞微斜 2024-10-29 01:30:17

当我查找具有“不真实”条件(例如 false 或 nil)的记录时,我要做的是:

Post.where(["(hidden IS NULL) OR (hidden = ?)", false])

What I do when I'm looking for records with a "not true" condition (eg, false or nil) is:

Post.where(["(hidden IS NULL) OR (hidden = ?)", false])
木森分化 2024-10-29 01:30:17

最后,我们有了 Rails 7 的方法 invert_where

irb> Post.where(:hidden => true).invert_where.to_sql
"SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"hidden\" != 1"

请检查此提交参考了解更多详情。

Finally we have the method invert_where with Rails 7.

irb> Post.where(:hidden => true).invert_where.to_sql
"SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"hidden\" != 1"

Please check this commit reference for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文