Mysql

如果在更新的派生表中,則忽略 Order by(僅在 MYSQL 5.7 中)

  • September 4, 2019

我有一個更新來修復表中的位置值。該更新在 MYSQL 5.5 中執行良好,但在升級到 MYSQL 5.7 後它不再執行。現在,派生表中的“order by”被忽略了。因此,這些行是基於主鍵更新的,而不是按順序更新的。

有人可以幫助我嗎?為什麼在 MYSQL 5.7 中忽略 order by 以及如何修復它?

謝謝!!!

舊位置值

ImageId     Position
389         0
390         6
391         4
392         1

固定後的新位置值 (MYSQL 5.5)

ImageId     Position
389         1
390         4
391         3
392         2

固定後的新位置值 (MYSQL 5.7)

ImageId     Position
389         1
390         2
391         3
392         4

更新

UPDATE  Image as t1
       INNER JOIN  (
                   SELECT  t.*, @rownum := @rownum + 1 AS newPosition
                   FROM    Image t, (SELECT @rownum := 0) r
                   ORDER   BY t.Position
                   ) as td
           ON t1.ImageId = td.ImageId SET     t1.Position= td.newPosition

SQL 中的派生表是一個集合,根據定義,集合沒有行順序。您嘗試(@rownum := @rownum + 1)在集合中使用命令式計算一開始是錯誤的,雖然它可能已經工作了一段時間,但正如您現在意識到的那樣,不能保證這一點。如果您嘗試使用類似的查詢,大多數數據庫引擎將(正確地)引發錯誤。

您所描述的需求已通過 MySQL 8 支持的視窗排名功能得到解決。如果您可以升級到該功能,您的解決方案將使用ROW_NUMBER () OVER(PARTITION BY ImageID ORDER BY Position).

如果您不能使用版本 8,則唯一有保證的解決方案是使用相關子查詢,類似於:

免責聲明 - 由於您沒有提供 DDL 和範例數據,以下解決方案未經測試

UPDATE  Image as t1
SET     Position = (
                   SELECT COUNT(*) 
                   FROM Image AS t2 
                   WHERE t1.ImageID = t2.ImageID 
                         AND 
                         t1.Position <= t2.position
                   );

請注意,對於大型表,此解決方案可能性能不佳,但由於它遵循 SQL 集規則,因此無論版本如何都能保證工作。

這是有效的 ANSI SQL 語法。MySQL 具體可能需要一些調整。

伺服器知道子查詢中的 ORDER BY 沒有意義,並將其刪除。它需要深入分析才能理解由於變數的使用而排序是有意義的。

您可以通過添加到您的子查詢來驗證這一點LIMIT N,其中 N 小於記錄數…

最簡單的解決方案是臨時定義Position為PRIMARY KEY,重新列舉記錄,然後恢復PK。但這需要值Position是唯一的而不是 NULL。

引用自:https://dba.stackexchange.com/questions/244353