Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Attribuer au hasard un lieu de travail et chaque lieu ne doit pas dépasser le nombre d'employés désignés

Peut-être quelque chose comme ça :

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)

Cela devrait tenter de faire correspondre les employés au hasard en fonction de leur désignation en supprimant le même poste actuel et la même maison, et ne pas attribuer plus que ce qui est spécifié dans chaque colonne pour la désignation. Cependant, cela pourrait renvoyer le même employé pour plusieurs lieux, car ils pourraient correspondre à plus d'un en fonction de ce critère.

MODIF : Après avoir vu votre commentaire sur le fait de ne pas avoir besoin d'une requête unique très performante pour résoudre ce problème (ce dont je ne suis même pas sûr qu'il soit même possible), et puisqu'il semble s'agir davantage d'un processus "ponctuel" que vous serez appelant, j'ai écrit le code suivant à l'aide d'un curseur et d'une table temporaire pour résoudre votre problème d'affectation :

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'idée de base est qu'il parcourt les employés, dans un ordre aléatoire, et attribue à chacun un lieu aléatoire qui répond aux critères de différents domiciles et affectations actuelles, ainsi que le contrôle du montant attribué à chaque lieu pour chaque désignation. pour s'assurer que les emplacements ne sont pas "sur-affectés" pour chaque rôle.

Cet extrait n'est pas modifient en fait vos données. Le dernier SELECT L'instruction renvoie simplement les affectations proposées. Cependant, vous pouvez très facilement le modifier pour apporter des modifications réelles à votre Employee tableau en conséquence.