Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Assegnare in modo casuale il luogo di lavoro e ogni luogo non deve superare il numero di dipendenti designati

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.