Reputation: 149
I have a simple MySQL 8 table like this:
CREATE TABLE IF NOT EXISTS `test_codes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`segment_id` int(11) unsigned NOT NULL,
`code_id` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
);
The table is populated with some random values
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('2');
INSERT INTO `test_codes` (`segment_id`) VALUES ('2');
INSERT INTO `test_codes` (`segment_id`) VALUES ('2');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
INSERT INTO `test_codes` (`segment_id`) VALUES ('1');
My applications has the following task: A request comes with an array of codes eg [1,200,10,18] and I need to get 4 rows (equal to array size) from the database where the code = 0 and update the code_id at each row with the values 1,200, 10, 18 transitionally.
A concurrent request that wants to update the code from another running thread, should not access the selected rows of the first thread.
How can I do this?
After the update the first selected row will have code_id 1, the second selected row code_id 200, the third 10 and the last one 18. In other words the task must find rows with unassigned codes (code_id=0) and set a value to each row.
Link: http://sqlfiddle.com/#!9/60e555/1
Upvotes: 0
Views: 105
Reputation: 1269513
MySQL doesn't support arrays. I would suggest that you first load the array into a table. This is just a convenience, but it is handy.
Then you can use a complex update
with join
to handle this:
update test_codes tc join
(select tc2.*,
row_number() over (order by rand()) as seqnum
from test_codes tc2
) tc2
on tc2.id = tc.id join
(select nc.*,
row_number() over (order by code_id) as seqnum
from new_codes nc
) nc
on tc2.seqnum = nc.seqnum
set tc.code_id = nc.code_id;
EDIT:
You can construct the query directly from the codes:
update test_codes tc join
(select tc2.*,
row_number() over (order by rand()) as seqnum
from test_codes tc2
) tc2
on tc2.id = tc.id join
(select ? as code, 1 as seqnum union all
select ? as code, 2 union all
. . .
) nc
on tc2.seqnum = nc.seqnum
set tc.code_id = nc.code_id;
Upvotes: 0
Reputation: 22811
You can do it with a single statement which you may build in the app
update test_codes
join
(
select id, row_number() over (order by id) rn
from test_codes
where code_id = 0
) t on t.id = test_codes.id
join (
-- a table of new values with their positions
select 1 rn, 1 val union all
select 2, 200 union all
select 3, 10 union all
select 4, 18
) v on v.rn = t.rn
set code_id = v.val
Upvotes: 1