Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Weisen Sie den Arbeitsort nach dem Zufallsprinzip zu und jeder Standort sollte die Anzahl der festgelegten Mitarbeiter nicht überschreiten

Vielleicht so etwas:

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)

Das sollte versuchen, Mitarbeiter zufällig auf der Grundlage ihrer Bezeichnung abzugleichen, wobei dieselbe aktuelle Posting und Heimat verworfen wird, und nicht mehr als das zuzuweisen, was in jeder Spalte für die Bezeichnung angegeben ist. Dies könnte jedoch denselben Mitarbeiter für mehrere Plätze zurückgeben, da er basierend auf diesen Kriterien mehr als einem entsprechen könnte.

BEARBEITEN: Nachdem Sie Ihren Kommentar gesehen haben, dass Sie keine leistungsstarke einzelne Abfrage benötigen, um dieses Problem zu lösen (was meiner Meinung nach überhaupt nicht möglich ist), und da es eher ein "einmaliger" Prozess zu sein scheint, der Sie sein werden Als ich angerufen habe, habe ich den folgenden Code mit einem Cursor und einer temporären Tabelle geschrieben, um Ihr Problem der Zuweisungen zu lösen:

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

Die Grundidee ist, dass es in zufälliger Reihenfolge über die Mitarbeiter iteriert und jedem einen zufälligen Ort zuweist, der die Kriterien unterschiedlicher Wohnorte und aktueller Posten erfüllt, sowie die Menge steuert, die jedem Ort für jede Bezeichnung zugewiesen wird um sicherzustellen, dass die Standorte nicht für jede Rolle "überbelegt" werden.

Dieses Snippet nicht ändern Sie Ihre Daten jedoch tatsächlich. Das letzte SELECT -Anweisung gibt nur die vorgeschlagenen Zuweisungen zurück. Sie können es jedoch sehr einfach ändern, um tatsächliche Änderungen an Ihrem Employee vorzunehmen Tabelle entsprechend.