Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Atribua aleatoriamente o local de trabalho e cada local não deve exceder o número de funcionários designados


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.