我遇到了一个更新语句应该(据我所知)更新5行的问题(我在临时表中选择了5行,并在更新语句中使用了INNER JOIN)
但是,在运行更新语句时,它会更新可能已选择到临时表中的所有内容,而不仅仅是临时表本身的联接内容。
我在选择语句中使用DT[which(rowSums(mapply(`%in%`, DT[, names(param), with = FALSE],
param)) == length(param)), ]
# a b c d
#1: 1 3 5 1
#2: 3 3 7 3
代码来锁定行,(因为我希望一次将多个查询针对该表,(注意删除不会改变错误。效果)
我已经概括了整个代码库,并且仍然具有相同的效果,在过去的几天中,我一直在研究它,并且我确定这只是我必须做的愚蠢的事情
代码说明
FOR UPDATE
用于存储数据并显示已被外部程序使用的表。
TABLE `data`.`data_table
调试代码以填充上表。
Stored Procedure `admin`.`func_fill_table
旨在检索批量记录的实际代码,将其标记为已拾取,然后将其返回给外部应用程序。
基本设置代码
Stored Procedure `data`.`func_get_data
过程创建
DROP TABLE IF EXISTS `data`.`data_table`;
DROP PROCEDURE IF EXISTS `admin`.`func_fill_table`;
DROP PROCEDURE IF EXISTS `data`.`func_get_data`;
DROP SCHEMA IF EXISTS `data`;
DROP SCHEMA IF EXISTS `admin`;
CREATE SCHEMA `admin`;
CREATE SCHEMA `data`;
CREATE TABLE `data`.`data_table` (
`identification_field_1` char(36) NOT NULL,
`identification_field_2` char(36) NOT NULL,
`identification_field_3` int(11) NOT NULL,
`information_field_1` int(11) NOT NULL,
`utc_action_time` datetime NOT NULL,
`utc_actioned_time` datetime DEFAULT NULL,
PRIMARY KEY (`identification_field_1`,`identification_field_2`,`identification_field_3`),
KEY `NC_IDX_data_table_action_time` (`utc_action_time`)
);
运行代码
DELIMITER //
CREATE PROCEDURE `admin`.`func_fill_table`(
IN records int
)
BEGIN
IF records < 1
THEN SET records = 50;
END IF;
SET @processed = 0;
SET @action_time = NULL;
WHILE @processed < records
DO
SET @action_time = DATE_ADD(now(), INTERVAL FLOOR(RAND()*(45)-10) MINUTE);#time shorter for temp testing
SET @if_1 = UUID();
SET @if_2 = UUID();
INSERT INTO data.data_table(
identification_field_1
,identification_field_2
,identification_field_3
,information_field_1
,utc_action_time
,utc_actioned_time)
VALUES (
@if_1
,@if_2
,FLOOR(RAND()*5000+1)
,FLOOR(RAND()*5000+1)
,@action_time
,NULL);
SET @processed = @processed +1;
END WHILE;
END
//
CREATE PROCEDURE `data`.`func_get_data`(
IN batch int
)
BEGIN
IF batch < 1
THEN SET batch = 1; /*Minimum Batch Size of 1 */
END IF;
DROP TABLE IF EXISTS `data_set`;
CREATE TEMPORARY TABLE `data_set`
SELECT
`identification_field_1` as `identification_field_1_local`
,`identification_field_2` as `identification_field_2_local`
,`identification_field_3` as `identification_field_3_local`
FROM `data`.`data_table`
LIMIT 0; /* Create a temp table using the same data format as the table but insert no data*/
SET SESSION sql_select_limit = batch;
INSERT INTO `data_set` (
`identification_field_1_local`
,`identification_field_2_local`
,`identification_field_3_local`)
SELECT
`identification_field_1`
,`identification_field_2`
,`identification_field_3`
FROM `data`.`data_table`
WHERE
`utc_actioned_time` IS NULL
AND `utc_action_time` < NOW()
FOR UPDATE; #Select out the rows to process (up to batch size (eg 5)) and lock those rows
UPDATE
`data`.`data_table` `dt`
INNER JOIN
`data_set` `ds`
ON (`ds`.`identification_field_1_local` = `dt`.`identification_field_1`
AND `ds`.`identification_field_2_local` = `dt`.`identification_field_2`
AND `ds`.`identification_field_3_local` = `dt`. `identification_field_3`)
SET `dt`.`utc_actioned_time` = NOW();
# Update the table to say these rows are being processed
select ROW_COUNT(),batch;
#Debug output for rows altered (should be maxed by batch number)
SELECT * FROM
`data`.`data_table` `dt`
INNER JOIN
`data_set` `ds`
ON (`ds`.`identification_field_1_local` = `dt`.`identification_field_1`
AND `ds`.`identification_field_2_local` = `dt`.`identification_field_2`
AND `ds`.`identification_field_3_local` = `dt`. `identification_field_3`);
# Debug output of the rows that should have been modified
SELECT
`identification_field_1_local`
,`identification_field_2_local`
,`identification_field_3_local`
FROM
`data_set`; /* Output data to external system*/
/* Commit the in process field and allow other processes to access thoese rows again */
END;
//
答案 0 :(得分:1)
您滥用sql_select_limit设置:
要从SELECT语句返回的最大行数。
它仅适用于select
语句(以限制发送给客户端的结果 ),不适用于insert ... select ...
。其目的是为了防止用户意外地被数以百万计的结果淹没,而不是其他limit
功能。
虽然通常不能为limit
使用变量,但是可以在存储过程中使用(对于MySQL 5.5 +):
LIMIT子句可用于约束SELECT语句返回的行数。 LIMIT接受一个或两个数字参数,它们都必须是非负整数常量,但以下情况除外:[...]
- 在存储的程序中,可以使用整数值的例程参数或局部变量来指定LIMIT参数。
因此,您可以使用
...
FROM `data`.`data_table`
WHERE `utc_actioned_time` IS NULL AND `utc_action_time` < NOW()
LIMIT batch
FOR UPDATE;