2

我需要以一种特殊的方式加入两个表。目前,连接是通过游标和循环完成的,我正在寻找一种更有效的方法来处理数据。

第一个表是待办事项列表:

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 中的同一工人完成。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_id 表中每一行的顺序,我执行以下操作:

  1. 选择cnt并工作
  2. 按照 Job_id 的顺序,我从 Jobs 表中搜索第一个可用的工人
  3. 用工人的工作更新 Jobs 表 cnt 次

我目前使用下面的 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

待办事项表:

待办事项表

结果工作表:

结果工作表

我现在正在寻找替换上述循环的有效查询或更新语句,我目前想不出一种方法来正确替换循环的上述行为。

4

1 回答 1

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
于 2013-08-21T15:48:10.253 回答