多分このようなもの:
select C.* from
(
select *, ROW_NUMBER() OVER(PARTITION BY P.PlaceID, E.Designation ORDER BY NEWID()) AS RandPosition
from Place as P cross join Employee E
where P.PlaceName != E.Home AND P.PlaceName != E.CurrentPosting
) as C
where
(C.Designation = 'Manager' AND C.RandPosition <= C.Manager) OR
(C.Designation = 'PO' AND C.RandPosition <= C.PO) OR
(C.Designation = 'Clerk' AND C.RandPosition <= C.Clerk)
これは、同じcurrentPostingとhomeを破棄する指定に基づいてランダムに従業員を照合することを試み、指定の各列で指定されている以上のものを割り当てないようにする必要があります。ただし、その基準に基づいて複数の場所に一致する可能性があるため、複数の場所で同じ従業員が返される可能性があります。
編集: この問題を解決するために高性能の単一クエリを必要としないというコメントを見た後(それが可能かどうかはわかりませんが)、それは「1回限りの」プロセスのように思われるためです。呼び出して、割り当ての問題を解決するために、カーソルと1つの一時テーブルを使用して次のコードを作成しました。
select *, null NewPlaceID into #Employee from Employee
declare @empNo int
DECLARE emp_cursor CURSOR FOR
SELECT EmpNo from Employee order by newid()
OPEN emp_cursor
FETCH NEXT FROM emp_cursor INTO @empNo
WHILE @@FETCH_STATUS = 0
BEGIN
update #Employee
set NewPlaceID =
(
select top 1 p.PlaceID from Place p
where
p.PlaceName != #Employee.Home AND
p.PlaceName != #Employee.CurrentPosting AND
(
CASE #Employee.Designation
WHEN 'Manager' THEN p.Manager
WHEN 'PO' THEN p.PO
WHEN 'Clerk' THEN p.Clerk
END
) > (select count(*) from #Employee e2 where e2.NewPlaceID = p.PlaceID AND e2.Designation = #Employee.Designation)
order by newid()
)
where #Employee.EmpNo = @empNo
FETCH NEXT FROM emp_cursor INTO @empNo
END
CLOSE emp_cursor
DEALLOCATE emp_cursor
select e.*, p.PlaceName as RandomPosting from Employee e
inner join #Employee e2 on (e.EmpNo = e2.EmpNo)
inner join Place p on (e2.NewPlaceID = p.PlaceID)
drop table #Employee
基本的な考え方は、従業員をランダムな順序で繰り返し、さまざまな家と現在の投稿の基準を満たすランダムな場所を各従業員に割り当て、各指定の各場所に割り当てられる金額を制御することです。役割ごとに場所が「過剰に割り当てられていない」ことを確認します。
このスニペットはありません ただし、実際にはデータを変更します。最後のSELECT
ステートメントは、提案された割り当てを返すだけです。ただし、非常に簡単に変更して、Employee
に実際の変更を加えることができます。 それに応じてテーブル。