使用另一个 table 的模数更新一个 table 的多行
Update multiple rows of one table using modulas of another table
create table queue(queue_id int primary key auto_increment, tele bigint);
insert into queue values
(null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
create table container (container_id int primary key auto_increment, queue_container_id int, source bigint);
insert into container values
(null, 1, 1000000001)
, (null, 1, 1000000002)
, (null, 1, 1000000003)
, (null, 1, 1000000004)
, (null, 1, 1000000005)
, (null, 2, 1000000003)
我的目标:
我想用适当的来源更新 tele 专栏 #.
我想将源#s 均匀地分配到队列中。一种约束,它必须只使用给定的queue_container_id。例如,如果我将 queue_container_id 设为 1,它只会使用那些源编号。队列应该填满所有电话号码。重复应首先尝试均匀分布。
困难的方法是获取所有 queue_ids 并一次更新每一行。我想知道这是否可以通过一个查询实现,因为一次可能要更新多达 100 万行。
一个选项使用 window 函数和算术。假设 queue_id
总是无间隙递增:
select *
from queue q
inner join (
select c.*,
row_number() over(order by container_id) rn,
count(*) over() cnt
from container c
where queue_container_id = 1
) c on (c.rn - 1) = (q.queue_id - 1) % c.cnt
这会将给定 queue_container_id
的容器均匀分布到队列中。
如果queue_id
不可靠,我们可以用row_number()
生成我们自己的序列:
select *
from (
select q.*,
row_number() over(order by queue_id) rn
from queue
) q
inner join (
select c.*,
row_number() over(order by container_id) rn,
count(*) over() cnt
from container c
where queue_container_id = 1
) c on (c.rn - 1) = (q.queue_id - 1) % c.cnt
在早期版本中,选项有限。如果您有大量行,使用子查询模拟 row_number()
和 window 计数将无法很好地扩展。一种替代方法是用户变量:
select *
from queue q
inner join (
select c.*, @rn := @rn + 1 rn
from (
select *
from container c
where queue_container_id = 1
order by container_id
) c
cross join (select @rn := 0) x
) c on (c.rn - 1) = (q.queue_id - 1) % @rn
用户变量使用起来很棘手,并且(最终!)计划在 MySQL 的未来版本中弃用。虽然上述解决方案适用于 MySQL 5.x,但我强烈建议升级到 MySQL 8.0,并使用 window 函数解决方案。这才是正确的做法。
create table queue(queue_id int primary key auto_increment, tele bigint);
insert into queue values
(null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
, (null, null)
create table container (container_id int primary key auto_increment, queue_container_id int, source bigint);
insert into container values
(null, 1, 1000000001)
, (null, 1, 1000000002)
, (null, 1, 1000000003)
, (null, 1, 1000000004)
, (null, 1, 1000000005)
, (null, 2, 1000000003)
我的目标: 我想用适当的来源更新 tele 专栏 #.
我想将源#s 均匀地分配到队列中。一种约束,它必须只使用给定的queue_container_id。例如,如果我将 queue_container_id 设为 1,它只会使用那些源编号。队列应该填满所有电话号码。重复应首先尝试均匀分布。
困难的方法是获取所有 queue_ids 并一次更新每一行。我想知道这是否可以通过一个查询实现,因为一次可能要更新多达 100 万行。
一个选项使用 window 函数和算术。假设 queue_id
总是无间隙递增:
select *
from queue q
inner join (
select c.*,
row_number() over(order by container_id) rn,
count(*) over() cnt
from container c
where queue_container_id = 1
) c on (c.rn - 1) = (q.queue_id - 1) % c.cnt
这会将给定 queue_container_id
的容器均匀分布到队列中。
如果queue_id
不可靠,我们可以用row_number()
生成我们自己的序列:
select *
from (
select q.*,
row_number() over(order by queue_id) rn
from queue
) q
inner join (
select c.*,
row_number() over(order by container_id) rn,
count(*) over() cnt
from container c
where queue_container_id = 1
) c on (c.rn - 1) = (q.queue_id - 1) % c.cnt
在早期版本中,选项有限。如果您有大量行,使用子查询模拟 row_number()
和 window 计数将无法很好地扩展。一种替代方法是用户变量:
select *
from queue q
inner join (
select c.*, @rn := @rn + 1 rn
from (
select *
from container c
where queue_container_id = 1
order by container_id
) c
cross join (select @rn := 0) x
) c on (c.rn - 1) = (q.queue_id - 1) % @rn
用户变量使用起来很棘手,并且(最终!)计划在 MySQL 的未来版本中弃用。虽然上述解决方案适用于 MySQL 5.x,但我强烈建议升级到 MySQL 8.0,并使用 window 函数解决方案。这才是正确的做法。