gpt4 book ai didi

sql - 两次加入同一个表时,Rails 3.1 范围被忽略

转载 作者:行者123 更新时间:2023-12-03 17:54:23 24 4
gpt4 key购买 nike

使用 rails 3.1.4 在不同的范围内两次加入同一个表时遇到问题。其中一个范围被完全忽略,包括 join 和 where 子句。此删除发生时不会出现错误或通知。

这是导致问题的简化示例:

Task 是一个标准的 rails 模型,与模型 SavedOutput 具有多态关系。 SavedOuput 用作缓存来存储复杂方法的结果。

任务模型如下所示:

class Task < ActiveRecord::Base
has_many :saved_outputs
scope :saved_lates, lambda { joins(:saved_outputs).where(
"saved_outputs.method" => "late?",
"saved_outputs.output" => true
)}
scope :saved_completes, lambda { joins(:saved_outputs).where(
"saved_outputs.method" => "complete?",
"saved_outputs.output" => true
)}
...

使用此代码,我可以调用 Task.saved_lates而不是调用像 Task.all.select(&:late?) 这样的东西假设缓存的数据是最新的。

问题是调用 Task.saved_lates.saved_completes不起作用。我相信 Rails 的重复查询检测会启动并删除第二个范围。即使没有发生这种情况,查询仍然会失败,因为如果不使用 MYSQL 中的别名,您将无法两次连接到同一个表。

我有一个手动编写的连接和表别名的部分解决方案。
  scope :saved_lates, lambda { joins("INNER JOIN saved_outputs AS so1 ON so1.object_type='Task' AND so1.object_id=tasks.id").where(
"so1.method" => "late?",
"so1.output" => true
)}
scope :saved_completes, lambda { joins(INNER JOIN saved_outputs AS so2 ON so2.object_type='Task' AND so2.object_id=tasks.id).where(
"so2.method" => "complete?",
"so2.output" => true
)}

这个解决方案的问题是别名 so1在整个项目中必须是唯一的。考虑到 SavedOutput 模型保存了许多不同模型的输出,我需要使用全局唯一 ID 或唯一哈希系统来标记别名。

是否有从查询中静默删除范围的解决方案?
有没有办法强制 rails 在每个标准连接上创建一个唯一的表别名?
使用带有关联符号的连接范围作为参数是不好的做法吗?

这是我正在查看的完整示例:
class ScopeTest < ActiveRecord::Migration
def change
create_table :foos do |t|
t.string :name
t.boolean :active, :default => true
end

create_table :bars do |t|
t.integer :foo_id
t.boolean :method_value
end
end
end

class Foo < ActiveRecord::Base
has_many :bars
scope :ones, lambda { joins(:bars).where("bars.method_value" => true) }
scope :zeroes, lambda { joins(:bars).where("bars.method_value" => false) }
end

运行范围和链接范围的结果:
irb(main):022:0> Foo.ones.to_sql
=> "SELECT `foos`.* FROM `foos` INNER JOIN `bars` ON `bars`.`foo_id` = `foos`.`id` WHERE `bars`.`method_value` = 1"
irb(main):023:0> Foo.zeroes.to_sql
=> "SELECT `foos`.* FROM `foos` INNER JOIN `bars` ON `bars`.`foo_id` = `foos`.`id` WHERE `bars`.`method_value` = 0"
irb(main):024:0> Foo.ones.zeroes.to_sql
=> "SELECT `foos`.* FROM `foos` INNER JOIN `bars` ON `bars`.`foo_id` = `foos`.`id` WHERE `bars`.`method_value` = 0"
irb(main):025:0> Foo.zeroes.ones.to_sql
=> "SELECT `foos`.* FROM `foos` INNER JOIN `bars` ON `bars`.`foo_id` = `foos`.`id` WHERE `bars`.`method_value` = 1"

当我链接查询时,我想从两个范围中获取结果的交集。我希望 sql 具有与此相同的含义:
SELECT `foos`.* from `foos` 
INNER JOIN `bars` AS `bars1` ON `bars1`.`foo_id` = `foos`.`id`
INNER JOIN `bars` AS `bars2` ON `bars2`.`foo_id` = `foos`.`id`
WHERE `bars1`.`method_value` = 1 AND `bars2`.`method_value` = 0

我怎么做?

最佳答案

你怎么知道它不起作用? SQL 说正在发生什么?我只是模拟了一个模型...

class Foo < ActiveRecord::Base
has_many :bars
scope :one, lambda { joins(:bars).where('x = 1') }
scope :two, lambda { joins(:bars).where('x = 2') }
end

并在控制台中运行它......查询看起来很好......当然,它不会返回任何结果,因为条件无法满足,但一切都如我所料那样合并/链接。
Foo.one.two.to_sql
=> "SELECT `foos`.* FROM `foos`
INNER JOIN `bars` ON `bars`.`foo_id` = `foos`.`id`
WHERE (x = 1) AND (x = 2)"

这是使用 Rails 3.2.8 ......

关于sql - 两次加入同一个表时,Rails 3.1 范围被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13652589/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com