我有一个看起来像的表(减去不相关的列):
PRIMARY KEY(AUTO-INCREMENT,INT),
CLIENTID(INT),
CLIENTENTRYID(INT),
COUNT1(INT),
COUNT2(INT)
现在,CLIENTID和CLIENTENTRYID是一个独特的组合索引,可用作复制预防。
我使用PHP post输入到服务器。我的查询如下:
$stmt = $sql->prepare('INSERT INTO table (COUNT1,COUNT2,CLIENTID,CLIENTENTRYID) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE COUNT1=VALUES(COUNT1),COUNT2=VALUES(COUNT2)');
$stmt->bind_param("iiii",$value,$value,$clientid,$cliententryid);
SQL对象已启用自动提交。 “value”变量被重用,因为COUNT1和COUNT2中的值应始终相同。
好的 - 大部分时间都可以正常工作,但随机,我无法弄清楚为什么,它会在COUNT2中发布0 - 换一个完全不同的行。
任何想法可能会如何发生?我看不到一个模式(尝试失败后不会发生这种情况,这就是唯一索引存在的原因,因此新的尝试不会导致重复)。这似乎是完全随机的。
是否有一些我误解了关于UPPLICATE KEY UPDATE的内容?非常奇怪的是它错误地更新了一个不同的行 - 而不是你插入的行。
我意识到其他因素可能会影响这一点,但现在我试图排除我的SQL逻辑作为错误来源。
答案 0 :(得分:1)
除了auto_increment列上的PRIMARY KEY之外,表中只定义了一个UNIQUE键,并在 (CLIENTID,CLIENTENTRYID)
上定义,对吧?
表上没有定义触发器,对吧?
你(显然)使用带有绑定占位符的预准备语句。
如果这两列(CLIENTID和CLIENTENTRYID)被定义为NOT NULL或不是,那么这并不重要; MySQL将允许多行具有NULL值;并没有违反"唯一性"由UNIQUE约束强制执行。 (这与Oracle如何处理NULL值的唯一性"相同,但它与SQL Server强制执行的方式不同。)
我只是没有看到你所展示的陈述的任何方式,即:
INSERT INTO `mytable` (COUNT1,COUNT2,CLIENTID,CLIENTENTRYID) VALUES (?,?,?,?)
ON DUPLICATE KEY
UPDATE COUNT1 = VALUES(COUNT1)
, COUNT2 = VALUES(COUNT2)
...没有办法会导致表中的其他行被更新。
插入操作成功,或者它会抛出一个"重复键"例外。如果"重复键"抛出异常,语句捕获该异常,并执行UPDATE操作。
鉴于(CLIENTID,CLIENTENTRYID)
是表中唯一的唯一键(除了auto_increment列,此语句未引用),更新操作将等同于此语句:
UPDATE `mytable`
SET COUNT1 = ?
, COUNT2 = ?
WHERE CLIENTID = ?
AND CLIENTENTRYID = ?
...使用INSERT语句的VALUES子句中提供的值。
最重要的是,OP向我们展示的任何事情都没有问题。逻辑是合理的。除了这个SQL语句之外,还有别的东西。
OP代码在bind_param
调用中显示为使用标量(而不是数组元素)作为参数,因此通过引用传递的整个混乱不应该是一个问题。
根据OP告诉我们并向我们展示的所有内容,OP已经显示的SQL语句没有问题。报告的问题必须是其他,而不是SQL语句。
答案 1 :(得分:0)
查看MySQL doc,它说明了insert
语句
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
如果a和b列是唯一的,insert
等同于update
语句,WHERE
子句包含OR
而不是AND
:
UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
引用文档,
如果a = 1或b = 2匹配多行,则只更新一行。的在 一般情况下,您应该尽量避免使用ON DUPLICATE KEY UPDATE 具有多个唯一索引的表的子句。
希望这有帮助。
更新:
根据进一步的讨论,OP将考虑re-visiting existing database design。 OP还有另一个具有类似多个唯一索引规范的表,但使用INSERT IGNORE
没有相同的问题。
答案 2 :(得分:0)
我找到了答案。
正如大家在这里所说的那样,这是另一回事。出于一些完全奇怪的原因,我用来打开“添加新条目”的按钮以某种方式POST设置在表视图中的选定对象上设置到达= 0,与按钮无关。
这必须是我的故事板中某处的UI链接。
对不起,我浪费了你很多时间。至少我学到了更多关于SQL和索引的知识。
答案 3 :(得分:-2)
我认为问题在于您正在使用UPDATE COUNT1 = VALUES(COUNT1)中的值,COUNT2 = VALUES(COUNT2)尝试使用像这样
ON DUPLICATE KEY UPDATE COUNT1 = $v1,COUNT2 = $v2;