Php “获取MySQL中最后更新行的ID”技巧是如何工作的?

Php “获取MySQL中最后更新行的ID”技巧是如何工作的?,php,mysql,Php,Mysql,我试图选择表中最后更新的行id,然后我发现了这个问题 这个解决方案是可行的,但我不明白为什么我必须将@uids设置为null而不是空字符串。为什么此语句仅选择受影响的行而不是匹配的行,即使附加了limit子句。这是MySQL定义的行为吗?我应该查阅MySQL手册的哪一页 mysql> select * from transaction_test; +----+--------+------------+ | id | value1 | value2 | +----+--------

我试图选择表中最后更新的行id,然后我发现了这个问题

这个解决方案是可行的,但我不明白为什么我必须将@uids设置为null而不是空字符串。为什么此语句仅选择受影响的行而不是匹配的行,即使附加了limit子句。这是MySQL定义的行为吗?我应该查阅MySQL手册的哪一页

mysql> select * from transaction_test;
+----+--------+------------+
| id | value1 | value2     |
+----+--------+------------+
|  1 |      1 | 1460600984 |
|  2 |      2 | 1460598960 |
+----+--------+------------+
2 rows in set (0.00 sec)

mysql>  set @ids=null;update  transaction_test set value2=unix_timestamp(now()) where 1=1 and  ( SELECT @ids:=concat_ws(',',@ids,value1)  ) limit 1;select @ids;
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0

+------+
| @ids |
+------+
| 1    |
+------+
1 row in set (0.00 sec)

mysql>  set @ids='';update  transaction_test set value2=unix_timestamp(now()) where 1=1 and  ( SELECT @ids:=concat_ws(',',@ids,value1)  ) limit 1;select @ids;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

+------+
| @ids |
+------+
| ,1,2 |
+------+
1 row in set (0.00 sec)
如果将@uids初始化为空字符串,那么concatws',fooid,@uids在执行第一次连接时将生成fooid,而不仅仅是fooid,因为它将连接fooid并在它们之间使用逗号。但是,当CONCAT_WS的任何参数为NULL时,它将被完全忽略,并且在它和相邻元素之间不会放置逗号

它只选择受影响的行,因为它会执行短路。这意味着参数是从左到右求值的,如果第一个参数为FALSE,则根本不求值第二个参数。所以它只执行@uids:=。。。fooid>5时的赋值为TRUE

如果您有一个LIMIT子句,那么行为取决于您排序所依据的列是否被索引。如果是,它将按顺序扫描索引,然后计算WHERE子句,并在达到限制计数时停止,因此只有限制内的行才会包含在@uids中。或者,如果没有ORDERBY子句,它只扫描表,直到达到限制

但是,您不能可靠地依赖于此,它取决于查询优化器如何分析查询

但是,如果排序列没有索引,或者查询优化器无法执行上述优化,它可能必须扫描整个表,将与WHERE子句匹配的所有行选择到一个临时表中,然后对该临时表执行排序。在这种情况下,@uids将包含所有匹配的ID,而不仅仅是限制内的ID。您可以通过使用子查询来解决此问题

SET @uids := null;
UPDATE footable AS t1
JOIN (SELECT fooid
      FROM footable
      WHERE fooid > 5
      ORDER BY somecolumn
      LIMIT 10) AS t2
ON t1.fooid = t2.fooid
SET t1.foo = 'bar'
WHERE @uids := CONCAT_WS(',', fooid, @uids);
SELECT @uids;
如果将@uids初始化为空字符串,那么concatws',fooid,@uids在执行第一次连接时将生成fooid,而不仅仅是fooid,因为它将连接fooid并在它们之间使用逗号。但是,当CONCAT_WS的任何参数为NULL时,它将被完全忽略,并且在它和相邻元素之间不会放置逗号

它只选择受影响的行,因为它会执行短路。这意味着参数是从左到右求值的,如果第一个参数为FALSE,则根本不求值第二个参数。所以它只执行@uids:=。。。fooid>5时的赋值为TRUE

如果您有一个LIMIT子句,那么行为取决于您排序所依据的列是否被索引。如果是,它将按顺序扫描索引,然后计算WHERE子句,并在达到限制计数时停止,因此只有限制内的行才会包含在@uids中。或者,如果没有ORDERBY子句,它只扫描表,直到达到限制

但是,您不能可靠地依赖于此,它取决于查询优化器如何分析查询

但是,如果排序列没有索引,或者查询优化器无法执行上述优化,它可能必须扫描整个表,将与WHERE子句匹配的所有行选择到一个临时表中,然后对该临时表执行排序。在这种情况下,@uids将包含所有匹配的ID,而不仅仅是限制内的ID。您可以通过使用子查询来解决此问题

SET @uids := null;
UPDATE footable AS t1
JOIN (SELECT fooid
      FROM footable
      WHERE fooid > 5
      ORDER BY somecolumn
      LIMIT 10) AS t2
ON t1.fooid = t2.fooid
SET t1.foo = 'bar'
WHERE @uids := CONCAT_WS(',', fooid, @uids);
SELECT @uids;

您是否对更新应用了限制?@MichaelBerkowski是的,我需要更新部分比赛,然后选择它们。表示***在SELECT语句中,每个SELECT表达式仅在发送到客户端时才计算***@MichaelBerkowski我尝试了空字符串,但它在limit子句中没有按预期工作。您是否将限制应用于更新?@MichaelBerkowski是的,我需要更新部分匹配,然后选择它们。表示***在SELECT语句中,每个SELECT表达式仅在发送到客户端时才计算***@MichaelBerkowski我尝试了空字符串,但它在limit子句中没有按预期工作。令人困惑的结果是,空字符串案例也选择了不受影响的行。我在问题中添加了我的测试,您可能会验证这确实很奇怪,它似乎会影响查询计划器。使用JOIN方法获得确定的结果。令人困惑的结果是,空字符串大小写也选择了未受影响的行。我在问题中添加了我的测试,您可能会验证这确实很奇怪,它似乎会影响查询计划器。使用JOIN方法来获得确定的结果。