Mysql
如果在更新的派生表中,則忽略 Order by(僅在 MYSQL 5.7 中)
我有一個更新來修復表中的位置值。該更新在 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。