嵌套连接的更新不适用于订单

Update of nested join not working with an order

好久了reader,第一次发贴。 (我做了一些深入的搜索,但找不到类似的东西——提前谢谢你)

我正在使用 ruby 和活动记录对一个项目进行编码,但我 运行 遇到无法 google 搜索为什么两件事的答案的情况发生。据我所知,第一件事是由于 rails 的一个已知错误而发生的。第二个,我不知道。

这是模拟代码:

class Object1 < ActiveRecord::Base
  has_many :object2s, foreign_key: :object1_id, :dependent => :delete_all
end

class Object2 < ActiveRecord::Base
  belongs_to :object1, class_name: "Object1"
end

对象 2 具有 object1_id 和日期的唯一索引。

我有一个更新因索引违规而失败:

Object1Controller 中的 ActiveRecord::RecordNotUnique#datechange

更新代码:

Object2.joins( :object1 ).where( object1: { :id => id } )**.order( obj2_date: ascdsc )**.update_all(
    "obj2_date = " + direction + "(obj2_date, INTERVAL " + difference.to_s + " month)")

索引在没有顺序的更新时被触发(上面添加了**),日期的更新方式导致了违规。在代码的其他地方,我指定了更新顺序,它将以不违反索引的方式更新它们。使用此对象,添加连接会导致第一个问题:

这是生成的(模拟)SQL:

UPDATE object2 SET obj2_date = date_sub(obj2_date, INTERVAL 1 month) 
WHERE object2.id IN (
    SELECT id FROM (
        SELECT object2.id FROM object2 INNER JOIN object1 ON object1.id = object2.object1_id WHERE <criteria> **ORDER BY object2.obj2_date ASC**
    )  __active_record_temp
)

如果我修改 SQL,我可以在 SQL 客户端中 运行 它,它将按预期工作。 [注:我移动了订单的位置]

UPDATE object2 SET obj2_date = date_sub(obj2_date, INTERVAL 1 month) 
WHERE object2.id IN (
    SELECT id FROM (
        SELECT object2.id FROM object2 INNER JOIN object1 ON object1.id = object2.object1_id WHERE <criteria>
    )  __active_record_temp
) **ORDER BY object2.obj2_date ASC**

问题 1: 订单被添加到错误的地方。我如何正确处理或解决它?

我认为这与这个错误有关:
https://github.com/rails/rails/issues/6769

问题二: 为什么会这样? ...select id 来自 (select id 来自 table) __temp_table...

WHERE object2.id IN (
    SELECT id FROM (
        SELECT object2.id FROM object2 INNER JOIN object1 ON object1.id = object2.object1_id WHERE <criteria> **ORDER BY object2.obj2_date ASC**
    )  __active_record_temp
)

这样不是更好吗:...select id 来自 table...

WHERE object2.id IN (
    SELECT object2.id FROM object2 INNER JOIN object1 ON object1.id = object2.object1_id WHERE <criteria> 
)

不再需要临时 table 只是为了在已经获取 ID 的情况下获取 ID?

谢谢。

我真的不明白为什么订单如此重要,但只需添加

LIMIT 18446744073709551615

在您的 ORDER mBY 后面

UPDATE object2 SET obj2_date = date_sub(obj2_date, INTERVAL 1 month) 
WHERE object2.id IN (
    SELECT DISTINCT id FROM (
        SELECT object2.id,object2.obj2_date FROM object2 INNER JOIN object1 ON object1.id = object2.object1_id WHERE <criteria> 
    )  __active_record_temp
ORDER BY obj2_date ASC LIMIT 18446744073709551615
)

为什么在没有 LIMIT 的情况下忽略 order by 的原因很简单,行根据定义是无序的,因此 ORDER BY 在没有限制的情况下被删除,

Mysql 让 ORDER BY 在特殊情况下保持不变

Object2.joins( :object1 ).where( object1: { :id => id } ).order( obj2_date: ascdsc ).limit(18446744073709551615).update_all(
    "obj2_date = " + direction + "(obj2_date, INTERVAL " + difference.to_s + " month)")

我不知道您可以在活动记录代码块中包含整个活动记录代码块。

这解决了这两个问题。代码:

Object2.where( id: __Object1.select( :id ).where( :parent_id => id )__ ).order( obj2_date: ascdsc ).update_all(
    "obj2_date = " + direction + "(obj2_date, INTERVAL " + difference.to_s + " month)")

自动生成此 SQL:

UPDATE object2 SET obj2_date = date_add(obj2_date, INTERVAL 1 month) 
WHERE object2.obj1_id IN (
    SELECT object1.id FROM object1 WHERE object1.parent_id = 15
) ORDER BY object2.obj2_date ASC