Talvez algo assim:
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)
Isso deve tentar combinar os funcionários aleatoriamente com base em sua designação, descartando o mesmo currentPosting e home, e não atribuir mais do que o especificado em cada coluna para a designação. No entanto, isso pode retornar o mesmo funcionário para vários locais, pois eles podem corresponder a mais de um com base nesse critério.
EDITAR: Depois de ver seu comentário sobre não ter necessidade de uma única consulta de alto desempenho para resolver esse problema (que não tenho certeza se é possível), e como parece ser mais um processo "único" que você será chamando, escrevi o seguinte código usando um cursor e uma tabela temporária para resolver seu problema de atribuições:
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
A ideia básica é que ele itere sobre os funcionários, em ordem aleatória, e atribua a cada um um Local aleatório que atenda aos critérios de residência diferente e postagem atual, além de controlar a quantidade atribuída a cada local para cada Designação para garantir que os locais não sejam "atribuídos em excesso" para cada função.
Este snippet não realmente alterar seus dados embora. O
SELECT
final A instrução apenas retorna as atribuições propostas. No entanto, você pode alterá-lo facilmente para fazer alterações reais em seu Employee
tabela em conformidade.