sql >> Database >  >> RDS >> Sqlserver

Wijs willekeurig een werklocatie toe en elke locatie mag het aantal aangewezen werknemers niet overschrijden

Misschien zoiets als dit:

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)

Dat zou moeten proberen om werknemers willekeurig te matchen op basis van hun aanduiding, waarbij dezelfde huidige Posting en thuis worden weggegooid, en niet meer toewijzen dan wat in elke kolom voor de aanduiding is gespecificeerd. Dit kan echter dezelfde medewerker voor meerdere plaatsen retourneren, omdat ze op basis van die criteria meer dan één kunnen matchen.

BEWERKEN: Na het zien van uw opmerking over het niet nodig hebben van een goed presterende enkele query om dit probleem op te lossen (waarvan ik niet zeker weet of het zelfs mogelijk is), en aangezien het meer een "eenmalig" proces lijkt te zijn dat u zult zijn terwijl ik belde, heb ik de volgende code geschreven met een cursor en een tijdelijke tabel om je probleem met opdrachten op te lossen:

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

Het basisidee is dat het de werknemers herhaalt, in willekeurige volgorde, en aan elk een willekeurige plaats toewijst die voldoet aan de criteria van verschillende thuis- en huidige plaatsingen, en ook het bedrag controleert dat aan elke plaats voor elke aanwijzing wordt toegewezen om ervoor te zorgen dat de locaties niet "over-toegewezen" worden voor elke rol.

Dit fragment niet daadwerkelijk uw gegevens wijzigen. De laatste SELECT statement retourneert alleen de voorgestelde toewijzingen. U kunt het echter heel gemakkelijk wijzigen om daadwerkelijke wijzigingen aan te brengen in uw Employee tabel dienovereenkomstig.



  1. Converteer een UTC-tijdzone in postgresql naar EST (lokale tijd)

  2. Hoe opeenvolgende rijen samen te groeperen in SQL door meerdere kolommen

  3. Subgegevens ophalen uit een lijst met faciliteiten

  4. MySQL of voorwaarde