我有这样的查询:
SET @uids = '';
INSERT INTO tbl1 (name,used,is_active)
VALUES (1,0,0),(2,0,0),(24,0,0)
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id)
, used = (SELECT @uids := concat_ws(',', LAST_INSERT_ID(), @uids))
, used = used+1
, is_active = CASE WHEN used > 3 THEN 1 ELSE 0 END;
SELECT @uids;
请参阅here以了解获取更新行ID的方法。
我得到了更新的行ID'在@uids
中,如果它更新了任何行,但是如果插入了一行,我就无法获得该行的ID。那么如何获得插入的行ID和更新的行ID?
如何在(SELECT @uids := concat_ws(',', LAST_INSERT_ID(), @uids))
之前的插入中执行ON DUPLICATE KEY...
?
答案 0 :(得分:1)
您无法执行此操作,因为在插入需要@uids
子句的情况下无法填充select
并且您不允许在其中使用select
子句insert
语句,除非您的查询可以转换为INSERT ... SELECT
。
只要您不尝试插入可能导致更新和插入的混合值(,这可能是您),您可以采用一种令人讨厌但安全的方式:
SET @uids := '';
INSERT INTO `tbl1` (name, used, is_active)
VALUES (1,0,0),(2,0,0),(24,0,0)
ON DUPLICATE KEY UPDATE
is_active = CASE WHEN used > 3 THEN 1 ELSE 0 END,
id = LAST_INSERT_ID(id),
used = used + 1,
id = (SELECT @uids := concat_ws(',', LAST_INSERT_ID(), @uids));
SELECT @uids, LAST_INSERT_ID() as f, MAX(id) as l from `tbl1`;
不是那么棘手,最后你有两个值:
LAST_INSERT_ID() as f
是第一个插入的行ID MAX(id) as l
因此,通过这两个边界,您可以完全插入行ID。说它有缺点,即使行只受更新语句的影响,你总是有一个LAST_INSERT_ID()
值。但是,当您使用php标记问题时,有mysqli_affected_rows
时有机会从multi_query
获益,但我无法从mysqli_affected_rows
生成预期的返回值{是documented by MySQL:
对于
INSERT ... ON DUPLICATE KEY UPDATE
语句,受影响的行 如果将行作为新行插入,则每行的值为1;如果是,则为2 更新现有行,如果现有行设置为更新,则为0 当前价值。
您可以自己尝试一下,看看它是否有效。如果您获得了预期的返回值,那么您可以了解您的查询是否已完成某些更新或插入并根据该查询读取结果
作为我的简短回答,没有正确的方法在同一个查询上下文中执行它但可能以编程方式执行它更整洁? (虽然我不打赌它的表现)
$values = [[1, 0, 0], [2, 0, 0], [24, 0, 0]];
$insertIDs = [];
$updateIDs = [];
foreach ($values as $v) {
$insert = $mysqli->prepare("INSERT INTO `tbl1` (name, used, is_active) VALUES (?, ?, ?)");
$insert->bind_param('ddd', $v[0], $v[1], $v[2]);
$insert->execute();
if ($insert->affected_rows == -1) {
$update = $mysqli->prepare("UPDATE `tbl1` SET id = LAST_INSERT_ID(id), used = used + 1, is_active = CASE WHEN used > 3 THEN 1 ELSE 0 END WHERE name = ?"); // considering `name` as a unique column
$update->bind_param('d', $v[0]);
$update->execute();
if ($update->affected_rows == 1) {
$updateIDs[] = $update->insert_id;
}
} else {
$insertIDs[] = $insert->insert_id;
}
}
var_dump($updateIDs);
var_dump($insertIDs);
示例输出:
array(1) {
[0]=>
int(140)
}
array(1) {
[0]=>
int(337)
}
另一种解决方法可能是使用MySQL triggers。通过在表AFTER INSERT
上创建tbl1
触发器,您可以存储ID以供日后使用:
CREATE TRIGGER trigger_tbl1
AFTER INSERT
ON `tbl1` FOR EACH ROW
BEGIN
UPDATE `some_table` SET last_insert_ids = concat_ws(',', LAST_INSERT_ID(), last_insert_ids) WHERE id = 1;
END;