Може би нещо подобно:
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, и да не присвоява повече от това, което е посочено във всяка колона за обозначението. Това обаче може да върне един и същ служител за няколко места, тъй като те биха могли да съответстват на повече от едно въз основа на тези критерии.
РЕДАКТИРАНЕ: След като видях коментара ви за липсата на нужда от високоефективна единична заявка за решаване на този проблем (което не съм сигурен, че дори е възможно), и тъй като изглежда, че е по-скоро „еднократен“ процес, вие ще бъдете обаждайки се, написах следния код, използвайки курсор и една временна таблица, за да разреша проблема ви с присвояванията:
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
таблица съответно.