PHP / MySQLI:affected_rows的奇怪读数

时间:2014-04-16 10:45:13

标签: php mysql sql mysqli

我试图辨别replace into查询是否导致直接写入,或者首先删除然后写入。

The MySQL docs say受影响的行数应该在前者的情况下返回1,在后者的情况下应该返回1:

  

受影响的行计数可以轻松确定是否更新REPLACE   只添加了一行或者它是否也替换了任何行:检查是否   计数为1(已添加)或更高(已替换)。

但是,对于我来说,通过PHP和MySQLI执行此操作时,无论我的查询是直接写入还是首先删除然后写入,值都始终为1。

我有一张桌子" foo"使用一列:varchar也是主键。所以从一开始就是空的。我跑:

$sql = "REPLACE INTO foo VALUES('bar');"
$db->query($sql); //$db is an instantiated and working MySQLI instance
echo $db->affected_rows;

这给了我" 1" - 公平地说,这是一个直写。但是,如果我再次运行相同的查询,它应该给我" 2",对吗?首先删除该行,然后重新插入,因为主键是相同的。因此,2个受影响的行。

顺便说一句,我已经尝试了基本查询和准备好的陈述,即

$sql = "REPLACE INTO foo VALUES(?)";
$stmt = $db->prepare($sql);
$bar = "bar";
$stmt->bind_param('s', $bar);
$stmt->execute();
echo $stmt->affected_rows; //still 1

有什么想法!?

1 个答案:

答案 0 :(得分:0)

根据我的实验和发现:

就像手册中所说的那样,如果REPLACE删除了一行并插入到位而不是INSERT,它会显示更多的数字。请注意文档:

  

请注意,除非表具有PRIMARY KEY或UNIQUE索引,否则使用   REPLACE语句毫无意义。它等同于INSERT,   因为没有索引可用于确定是否有新行   复制另一个。

因此,在replace语句中,您必须传递主键或唯一键列的值。从我看来,你只传递一个值。您需要为REPLACE指定一个键值,以便在替换/插入之前识别应检查哪个行值。

另一个有趣的观点是:

  

如果单行可以替换多个旧行   该表包含多个唯一索引和新行重复项   不同唯一索引中不同旧行的值。

这会产生大于2的数字,并且当您向其传递多个唯一列值时就是这种情况。


在运行了几个测试后,只传递了你所做的唯一键值,这就是我发现的:

1)如果您的其他列包含某些值(非默认值)并且您正在使用REPLACE语句仅传递唯一键值,则会设置所有其他列值到他们的DEFAULT值,因此受影响的行 2 。 REPLACE删除现有行,因为该行包含REPLACE语句中未提及的值。

请注意以下文档:

  

所有列的值都取自中指定的值   REPLACE声明。任何缺少的列都设置为默认值   值,就像INSERT一样。

2)如果所有其他列值都是默认值,则使用仅传递唯一键值的REPLACE语句会导致 1 。现在, 1 的原因我相信可以成为以下之一:

  • 已进行更新(Update bar set foo=1 where foo=1成功时返回TRUE(1),但受影响的行数为0)

  • REPLACE永远不会返回0(假设返回-1)

所以基本上,你得到一个 1 ,因为你的所有其他列都已经设置了默认值,如果更改任何其他列值并再次运行相同的语句,你会发现结果是 2