我需要以特殊方式加入两个表。目前,连接是通过游标和循环完成的,我正在寻找一种更有效的方法来处理数据。
第一个表是待办事项列表:
create table todo
( todo_id int not null identity(1,1) primary key,
cnt int not null, -- how many units of work have to be completed?
work char(1) not null -- type of work, for example 'x', 'y', 'z'
);
例如,该表包含以下值
insert into todo (cnt, work) values (1, 'x'), (3, 'y'), (2, 'u'), (3, 'v'), (1, 'w');
这意味着工作'x'必须完成一次,工作'y'三次,依此类推。此todo表中的工作必须由Jobs表中的第一个“可用”Job_id的同一个worker完成。 todo表中的每个条目都会导致Jobs表中的“cnt”条目。
create table jobs
(job_id int not null identity(1,1) primary key,
worker char(1) not null, -- name of worker, for example 'A', 'B', 'C'
work char(1)
);
最初使用以下值填充Jobs表:
insert into jobs (worker) values
('A'),('B'),('C'),('A'),('C'),('B'),('A'),('B'),('C'),('A'),('B'),('C');
按照todo表中每行的todo_id的顺序,我执行以下操作:
我目前使用以下T-SQL代码来完成此任务:
DECLARE @Cnt int, @work char(1);
DECLARE @Worker char(1);
DECLARE myCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT cnt, work from todo
OPEN myCursor
FETCH NEXT FROM myCursor INTO @cnt, @work
WHILE @@FETCH_STATUS = 0 BEGIN
select top 1 @Worker=Worker from jobs where work is null;
update top(@cnt) j
set work=@work
from jobs j
where j.work is null and j.worker=@worker;
FETCH NEXT FROM myCursor INTO @cnt, @work
END
CLOSE myCursor
DEALLOCATE myCursor
todo table:
结果作业表:
我正在寻找一个有效的查询或更新语句来取代上面的循环,我现在想不出一种方法来正确地替换上面的循环行为。
答案 0 :(得分:0)
我在while循环中重写了光标,它可能表现得更好:
-->Variable Declarations
declare @minIterator int ,@maxIterator int,@outerIterator int, @outerLoopCounter int=0, @innerIterator int, @innerLoopCounter int=1, @worker char(1);
-->Max todo id
select @maxIterator = max(todo_id) from todo;
-->Min todo_id
select @minIterator = min(todo_id) from todo;
-->Number of times outer loop needs to execute
select @outerIterator = @maxIterator-@minIterator;
-->Outer Loop for todo items
while @OuterLoopCounter<=@outerIterator
begin
-->Set number of time innerLoop iterates
select @innerIterator = cnt from todo where todo_id=@minIterator;
-->Set worker to do the job
select @worker = worker from jobs where job_id=(select min(job_id) from jobs where work is null)
-->Inner Loop for count of each todo item
while @innerLoopCounter<=@innerIterator
begin
update j
set j.work=t.work
from
jobs j,
todo t
where
t.todo_id=@minIterator
and j.job_id=(select min(x.job_id) from jobs x where x.work is null and x.worker=@worker);
set @innerLoopCounter=@innerLoopCounter+1;
end
set @innerLoopCounter=1;
set @outerLoopCounter=@outerLoopCounter+1;
set @minIterator = @minIterator+1;
end
-->See Results
select * from jobs