sql >> Databasteknik >  >> RDS >> Sqlserver

Tilldela arbetsplats slumpmässigt och varje plats bör inte överstiga antalet utsedda anställda

Kanske något sånt här:

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)

Det bör försöka matcha anställda slumpmässigt baserat på deras beteckning som kasserar samma aktuella Posting och hem, och inte tilldela mer än vad som anges i varje kolumn för beteckningen. Detta kan dock returnera samma anställd för flera platser, eftersom de kan matcha mer än en baserat på det kriteriet.

EDIT: Efter att ha sett din kommentar om att du inte har ett behov av en högpresterande enskild fråga för att lösa detta problem (vilket jag inte är säker på är ens möjligt), och eftersom det verkar vara mer av en "engångsprocess" som du kommer att bli när jag ringde skrev jag upp följande kod med hjälp av en markör och en tillfällig tabell för att lösa ditt problem med tilldelningar:

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

Grundidén är att den itererar över de anställda, i slumpmässig ordning, och tilldelar var och en en slumpmässig plats som uppfyller kriterierna för olika hem och nuvarande utstationering, samt kontrollerar mängden som tilldelas varje plats för varje beteckning för att säkerställa att platserna inte är "övertilldelade" för varje roll.

Det här utdraget gör det inte faktiskt ändra din data dock. Den sista SELECT uttalandet returnerar bara de föreslagna uppdragen. Men du kan mycket enkelt ändra den för att göra faktiska ändringar av din Employee tabell därefter.



  1. Dela sträng med split_part på asiatiskt språk

  2. Övervakning av Percona-distribution för PostgreSQL - nyckelmått

  3. Hur man tar bort text mellan 2 tecken med query i MYSQL

  4. mysql hur man får 2:a högsta värdet med grupp av och i en vänster join