mySQL INSERT ... ON DUPLICATE KEY column = VALUE( column ) + 1 如何工作?
Posted
技术标签:
【中文标题】mySQL INSERT ... ON DUPLICATE KEY column = VALUE( column ) + 1 如何工作?【英文标题】:How does the mySQL INSERT ... ON DUPLICATE KEY column = VALUE( column ) + 1 work? 【发布时间】:2021-03-13 18:46:13 【问题描述】:请参阅第一个问题之后的此问题的更新部分。
我有两个表,一个用于包含 id、users_id、image、pcimagename 的视频,和 视频网址 列;另一个用于包含 id、users_id、file_name、user_file_name 和 usage_count 的图像strong> 列。
两个表的主键是 id 列,它们是自动递增的,但是两个 id 值彼此不相关。 images 表的 file_name 列也有一个唯一键。 usage_count 列的默认值为 1。
phpMyAdmin 显示以下有关我正在使用的 mysql 数据库的信息:
Database server
Server: Localhost via UNIX socket
Server type: MariaDB
Server version: 5.5.52-MariaDB - MariaDB Server
Protocol version: 10
Server charset: UTF-8 Unicode (utf8)
我的目标是,每当要从视频表中删除一行时,我想首先将视频表中的图像信息复制到图像表中,如果图像(特别是 file_name 列值)在 images 表中不存在,将 usage_count 设置为 1,但是,如果图像确实存在,我想增加 usage_count 减 1 并执行更新。我搜索了“mySQL INSERT or UPDATE”并想出了 INSERT ... ON DUPLCATE KEY UPDATE 变体,这似乎是我想要做的。
但是,我以前从未使用过 INSERT ... ON DUPLICATE KEY UPDATE ... 语句。查看MySQL INSERT ON DUPLICATE KEY UPDATE 和Insert into a MySQL table or update if exists 页面,我想到了以下内容;不幸的是,我现在可以连接到我的数据库,所以我无法确定它是否正确:
INSERT
INTO `photos`
( `users_id`, `file_name`, `user_file_name` )
SELECT `users_id`, `image`, `pcimagename`
FROM `videos`
WHERE `status` = \'Deleted\'
AND `last_updated_on` <= DATE_SUB( NOW(), INTERVAL 1 DAY )
AND `tracks_id` = 0
ON DUPLICATE KEY UPDATE usage_count = VALUES( usage_count ) + 1;
我的问题是:
语法是否正确,具体来说:
1a) ON DUPLICATE 短语的位置是否正确?
1b) 我是否需要将 SELECT 语句括在括号中,我已经看到了可以使用的示例和其他没有的示例。
UPDATE usage_count = VALUES(usage_count) + 1 短语是否会导致插入图像表的每一行在该行的预插入 usage_count 值上加 1,或者所有来自的行SELECT FROM videos 的值是否相同?我对 ON DUPLICAT 语句的这一部分实际上是如何工作的了解不多。大多数示例只是分配了一个固定值。
更新
在使用 Anina 提供的 dbFiddle 时,我注意到运行以下 INSERT 语句并没有像我预期的那样增加:
After several INSERT ... ON DUPLICATE KEY UPDATE ... statements the test
table contains:
id val test action comment
1 1 2 update
2 2 2 update
3 3 1 insert
Perform another INSERT ... ON DUPLICATE KEY UPDATE ... statement,
this time to increment val 1, expecting that the test column should increment to 3.
INSERT INTO test (val )
VALUES ( 1 )
ON DUPLICATE KEY UPDATE test = VALUES( test ) + 1,
action = 'update',
comment = 'Why isn''t test 3?';
However ....
id val test action comment
1 1 2 update Why isn't test 3?
2 2 2 update
3 3 1 insert
表的创建如下:
CREATE TABLE test ( id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY( ID ),
val INT NOT NULL, UNIQUE( val ),
test INT DEFAULT 1,
action VARCHAR( 10 ) DEFAULT 'insert',
comment VARCHAR( 30 ) );
谢谢
【问题讨论】:
ON DUPLICATE KEY UPDATE photos set usage_count = usage_count + 1;
手册页很清楚see the manual
UPDATE usage_count = VALUES( usage_count ) + 1
短语是否会导致插入图像表的每一行在行的预插入 usage_count
值上加 1,或者所有来自 @987654333 的行@ 被赋予相同的值? 既不是第一个也不是第二个。仔细阅读关于 VALUES() 函数操作的参考手册。
fiddle - 调查。
谢谢大家。 Anina,你的小提琴对我关于 ON DUPICATE KEY 阶段的 VALUES() 表达式如何工作的问题很有帮助。
RiggsFolly,我没有为 INSERT ... ON DUPLICATE KEY UPDATE 语句打开 MySQL 5.6 参考手册页面,因为对于 v5.6,手册页中该页面的最早版本,以及我正在使用的 mySQL 版本的一个过去版本,它没有回答我所有的问题,或者如果回答了,我觉得它不够清楚,所以我错过了我在发布的问题中提出的问题,这里。不是说明书的错。这就是为什么我在这里问我的问题。但是,感谢您为阅读此问题并希望了解有关该条款的任何人添加链接。
【参考方案1】:
更新答案:
为了使测试列超过 2,我在创建测试表之后添加了以下 UPDATE TRIGGER,在对现有行进行任何插入之前:
CREATE TRIGGER before_test_update
BEFORE UPDATE ON test FOR EACH ROW
BEGIN
SET new.test = old.test + 1;
END;
这会导致测试列将其在现有行中的值增加 1,而不是失败插入的测试值 (1) 增加 1(始终为 2)。
请参阅此dbLink 以获取说明其工作原理的示例。
但是,因为 ON DUPLICATE KEY 短语只是将 INSERT 转换为 UPDATE,实习生使用上述触发器来更正测试增量。当现有行中的任何列被更新时,实际的 UPDATE 也会调用相同的触发器,从而导致测试列值不正确。
mySQL 手册说:
With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the
row is inserted as a new row, 2 if an existing row is updated, and 0 if an
existing row is set to its current values. If you specify the
CLIENT_FOUND_ROWS flag to the mysql_real_connect() C API function when
connecting to mysqld, the affected-rows value is 1 (not 0) if an existing
row is set to its current values.
当 ON DUPLICARE KEY UPDATE 短语转换 INSERT 时,有没有办法使用 affected-rows 值为 2 的事实到 BEFORE UPDATE TRIGGER 或 AFTER UPDATE TRIGGER 中的 UPDATE 或其他方式来确定发生这种情况,而不是直接在 >UPDATE,其中 affected-rows 值为 1?
如果是这样,我如何从 TRIGGER 中获取 affected-rows 值?
注意:在我的代码中,我使用了来自子SELECT 的INSERT,因此可以在将值返回到我的程序之前添加多行。因此,我正在寻找一种在插入多行时运行的 Purely-mySQL 解决方案。
【讨论】:
您收到的帮助均未表明您需要添加触发器。你为什么这样做?您需要做的就是将您的更新声明更改为ON DUPLICATE KEY UPDATE usage_count = usage_count + 1;
感谢您的建议 gview,但我已经在使用该短语了。 BEFORE TRIGGER 是一种需要的解决方法,因为 usage_count/test 列值停止增加超过 2。
如果您确实在我的问题的更新部分查看了指向 dbFiddle 的链接,您会看到在最初添加到表后针对值 1 的插入都具有测试值 2 .我需要的是,如初始问题所述,测试值从 1 开始,使用该列的默认值,然后每次插入,通过 ON DUPLICATE ... 短语更改为 UPDAT,递增 1 ,从 1 到 2、2 到 3、3 到 4 等等。如果没有 BEFORE INSERT 触发器,就不会发生这种情况。我的答案中的 dbLink 通过添加 BEFORE TRIGGER 解决了这个问题。
但是,由于 ON DUPLICATE ... 短语仅将 INSERT 转换为 UPDATE 并不能完全起作用,因为当我更改任何列的值时,除了使用显式 UPDATE 语句进行测试时,触发器触发并且usage_count(或测试)列的值增加。在我的项目代码中,该列是usage_count。在 dbFiddle 示例中,测试列执行相同的功能。当 ON DUPLICATE 从 INSERT 切换到 UPDATE 时,我需要以某种方式只调用 BEFORE UPDATE TRIGGER。以上是关于mySQL INSERT ... ON DUPLICATE KEY column = VALUE( column ) + 1 如何工作?的主要内容,如果未能解决你的问题,请参考以下文章
Java上的MySQL“INSERT ... ON DUPLICATE KEY UPDATE”:如何区分插入/更新/无变化状态
MySQL中的`REPLACE`和`INSERT ... ON DUPLICATE KEY UPDATE`之间有啥实际区别?
MySQL--INSERT INTO ... ON DUPLICATE KEY UPDATE ...
mysql INSERT ... ON DUPLICATE KEY UPDATE语句