Forse qualcosa del genere:
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)
Ciò dovrebbe tentare di abbinare i dipendenti in modo casuale in base alla loro designazione scartando la stessa pubblicazione corrente e casa e non assegnare più di quanto specificato in ciascuna colonna per la designazione. Tuttavia, questo potrebbe restituire lo stesso dipendente per più posti, poiché potrebbero corrispondere a più di uno in base a tale criterio.
MODIFICA: Dopo aver visto il tuo commento sul non aver bisogno di una singola query ad alte prestazioni per risolvere questo problema (che non sono nemmeno sicuro sia possibile), e poiché sembra essere più un processo "una tantum", lo sarai chiamando, ho scritto il seguente codice usando un cursore e una tabella temporanea per risolvere il tuo problema di assegnazioni:
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
L'idea di base è che itera sui dipendenti, in ordine casuale, e assegna a ciascuno un posto casuale che soddisfi i criteri della diversa sede e della pubblicazione corrente, oltre a controllare l'importo che viene assegnato a ciascun posto per ciascuna designazione per garantire che le posizioni non siano "assegnate in eccesso" per ogni ruolo.
Questo snippet non in realtà altera i tuoi dati però. Il SELECT
finale l'istruzione restituisce solo gli incarichi proposti. Tuttavia, potresti facilmente modificarlo per apportare modifiche effettive al tuo Employee
tabella di conseguenza.