Reputation: 18786
Let me preface this with by saying that what I'm describing here was working just fine in Mysql 5.6.x and lower. Now we're trying to update to mysql 5.7 and finding an issue with this UPDATE statement.
We have a table that looks like this:
imagefile
----------
id int
itemId int
...
sequenceNumber int
updatedDate date
In our application it is necessary for users to reorder imageFiles within the Item. Our SQL to do that looks like this:
UPDATE imageFile f1
JOIN (
SELECT f2.id, (@row:=@row+1) rowNum
FROM imageFile f2, (SELECT @row:=0) dm
WHERE f2.itemId = 8035323
ORDER BY f2.sequenceNumber, f2.updatedDate
) rs ON f1.id = rs.id
SET f1.sequenceNumber = rs.rowNum;
If I run just the select part as a stand-alone query it produces this:
SELECT f2.id, f2.sequenceNumber, sqNum (@row:=@row+1) rowNum, updatedDate
FROM imageFile f2, (SELECT @row:=0) dm
WHERE f2.itemId = 8035323
ORDER BY f2.sequenceNumber, f2.updatedDate;
id sqNum rowNum updatedDate
| 9 | 1 | 1 |2018-04-16 18:39:12
| 8 | 2 | 2 |2018-04-16 18:38:42
| 7 | 3 | 3 |2018-04-16 18:37:03
| 6 | 4 | 4 |2018-04-16 18:37:28
| 5 | 5 | 5 |2018-04-16 18:36:37
| 4 | 6 | 6 |2018-04-16 18:38:16
| 3 | 7 | 7 |2017-09-12 16:59:20
Which is correct and exactly what I expect... After I run the UPDATE with the SELECT as the subquery/join I get this:
id sqNum rowNum updatedDate
| 3 | 1 | 1 |2017-09-12 16:59:20
| 4 | 2 | 2 |2018-04-16 18:38:16
| 5 | 3 | 3 |2018-04-16 18:36:37
| 6 | 4 | 4 |2018-04-16 18:37:28
| 7 | 5 | 5 |2018-04-16 18:37:03
| 8 | 6 | 6 |2018-04-16 18:38:42
| 9 | 7 | 7 |2018-04-16 18:39:12
Which is completely wrong and doesn't seem to follow any order by that I told it to. Obviously something changed in the new version of mysql. When I do the EXPLAIN for that query in each version it's different as well...
5.6.34
id select_type table type possible keys key key length ref rows extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 35 NULL
1 PRIMARY i1 eq_ref PRIMARY PRIMARY 4 rs.id 1 NULL
2 DERIVED <derived3> system NULL NULL NULL NULL 1 Using filesort
2 DERIVED i2 ref uc_ItemNumber, in_workspaceId uc_ItemNumber 4 const 35 Using where
3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
5.7.18
id select_type table type possible_keys key key_len ref rows extra
1 PRIMARY <derived2> ALL 35
1 UPDATE i1 eq_ref PRIMARY PRIMARY 4 rs.id 1
2 DERIVED i2 ref uc_ItemNumber, in_workspaceId uc_ItemNumber 4 const 35 Using temporary; Using filesort
2 DERIVED <derived3> ALL 1 Using join buffer (Block Nested Loop)
3 DERIVED No tables used
My question is how do I get this to go back to the previous/desired behavior?
Upvotes: 0
Views: 41
Reputation: 522386
I seem to recall that session variables should not be used/relied upon for MySQL DML statements. But the good news is that we can rewrite your query without session variables:
UPDATE imageFile f1
INNER JOIN
(
SELECT
f2.id,
(SELECT COUNT(*)
FROM imageFile t
WHERE t.itemId = 8035323 AND
(t.sequenceNumber < f2.sequenceNumber OR
t.sequenceNumber = f2.sequenceNumber AND
(t.updatedDate < f2.updatedDate OR
(t.updatedDate = f2.updatedDate AND t.id < f2.id)))) rowNum
FROM imageFile f2
WHERE f2.itemId = 8035323
) rs
ON f1.id = rs.id
SET f1.sequenceNumber = rs.rowNum;
Upvotes: 1