如何确定MySQL UPDATE是否实际上与WHERE子句匹配任何行?

时间:2014-03-21 05:37:16

标签: php mysql rows-affected

我想在PHP中运行类似的更新

// pseudocode
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
IF AFFECTED_ROWS == 1 THEN
UPDATE invoice_item SET price=? WHERE invoice_id=?

为了增加安全性,我附加了creater_id以确保代码仅在登录用户是发票创建者时才更新,否则系统将不会更新。

最初打算使用AFFECTED_ROWS检查此情况。但最终经过多次挫折之后,我意识到如果所有新值与旧值相同,AFFECTED_ROWS将返回0。这意味着即使我对invoice_item有不同的值,也不会更新它们。

除了在UPDATE之前执行SELECT之外,是否有SQL查询或PHP函数会告诉我UPDATE是否匹配任何行,以便我可以相应地更新invoice_item?

4 个答案:

答案 0 :(得分:1)

您可以使用ROW_COUNT(),如果您读到它,它会解释当连接到数据库时,您可以指定CLIENT_FOUND_ROWS标志,该标志将给出为更新找到的行数,无论它们是否具有相同的值您正在更新的内容。

希望这有帮助。

答案 1 :(得分:0)

我从我的代码中取得了这个,所以像$ link这样的东西需要到位 - 但它显示了你感兴趣的东西

function update() {
    $q = "UPDATE table SET field1=? WHERE field2 = $value"; 
    /* create a prepared statement */
    $stmt = mysqli_stmt_init($link);
    if (mysqli_stmt_prepare($stmt, $q)) {
        mysqli_stmt_bind_param($stmt, "s",  $field1);
        mysqli_stmt_execute($stmt);

        if(mysqli_stmt_errno($stmt)){
            echo("Sql Error: ".$q. ' Sql error #: '.mysqli_stmt_errno($stmt). ' - ' . mysqli_stmt_error($stmt);
            return false;
        }
        else{
            $numrows =  mysqli_stmt_affected_rows($stmt);
            if (mysqli_stmt_errno($stmt) == 0 || mysqli_stmt_errno($stmt) ==''){
                // numrows = -1 is flag no error and no rows affected
                $numrows = ($numrows ==0?-1:$numrows);
            }
            else{
                echo("Sql Error: ".$q. ' Sql error #: '.mysqli_stmt_errno($stmt). ' - ' . mysqli_stmt_error($stmt);
                return false;
            }
             /* close statement */
            mysqli_stmt_close($stmt);
            return $numrows;
        }
    }
}   

答案 2 :(得分:0)

根据ROW_COUNT()上的文档:

  

ROW_COUNT()返回上一个语句更改,删除或插入的行数(如果它是UPDATEDELETEINSERT。对于其他陈述,该值可能没有意义。

您的查询:

  

除了在UPDATE之前执行SELECT之外,是否有SQL查询或PHP函数会告诉我UPDATE是否匹配任何行

您还可以在ROW_COUNT()或任何其他UPDATEDDL声明中使用DML

示例:使用您的伪代码:

// pseudocode
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
IF ( ROW_COUNT() >= 1 ) THEN
   UPDATE invoice_item SET price=? WHERE invoice_id=?
END IF;

否则,您可以尝试:

UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
UPDATE invoice_item SET price=
       (case when ( row_count() >= 1 ) then ? else price end)
WHERE invoice_id=?;

在设置参数值之前,再次检查row_count()值以决定是否为1个或更多参数设置值。

答案 3 :(得分:0)

您可以将其恢复为1个查询,而不用担心受影响的行:

UPDATE
  invoice
  left join invoice_item on invoice_item.invoice_id = invoice.invoice_id
SET
  invoice.due_date = ?, -- the WHERE will only let this happen if it will be changed
  invoice_item.price = ? -- the WHERE will only let this happen if it will be changed
WHERE
  invoice.invoice_id = ?
  and invoice.creater_id = ?
  and invoice.due_date != ? -- here compare the new due_date to the one already in the db