sql >> Base de Datos >  >> RDS >> Sqlserver

Asigne aleatoriamente la ubicación de trabajo y cada ubicación no debe exceder el número de empleados designados

Tal vez algo como esto:

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)

Eso debería intentar hacer coincidir a los empleados al azar en función de su designación descartando la misma publicación actual y el hogar, y no asignar más de lo que se especifica en cada columna para la designación. Sin embargo, esto podría devolver al mismo empleado para varios lugares, ya que podrían coincidir con más de uno según ese criterio.

EDITAR: Después de ver su comentario acerca de no tener la necesidad de una consulta única de alto rendimiento para resolver este problema (que no estoy seguro de que sea posible), y dado que parece ser más un proceso "único" que será llamando, escribí el siguiente código usando un cursor y una tabla temporal para resolver su problema de asignaciones:

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

La idea básica es que itera sobre los empleados, en orden aleatorio, y asigna a cada uno un Lugar aleatorio que cumple con los criterios de diferentes domicilios y puestos actuales, además de controlar la cantidad que se asigna a cada lugar para cada Designación. para asegurarse de que las ubicaciones no estén "sobreasignadas" para cada rol.

Este fragmento no en realidad alterar sus datos sin embargo. El SELECT final declaración simplemente devuelve las asignaciones propuestas. Sin embargo, puede modificarlo muy fácilmente para realizar cambios reales en su Employee tabla en consecuencia.