2012-09-22 2 views
8

Sto tentando di selezionare posizioni casuali di inserimento/reclutamento di dipendenti all'interno di un elenco di luoghi, tutti i dipendenti sono già postati in questi luoghi, sto provando per generare un nuovo posto di post casuale per loro con la condizione "dove" che "la nuova posizione casuale del dipendente non sarà uguale al loro luogo di origine e selezionati casualmente. I dipendenti con la loro designazione devono essere inferiori o uguali a Place wise designation numbers from Places table"Assegnare in modo casuale la posizione di lavoro e ogni posizione non deve superare il numero di dipendenti designati

tabella dei dipendenti è:

EmpNo EmpName   CurrentPosting Home  Designation RandomPosting 
1  Mac    Alabama   Missouri  Manager  
2  Peter    California  Montana  Manager  
3  Prasad   Delaware   Nebraska  PO  
4  Kumar    Indiana   Nevada  PO  
5  Roy    Iowa    New Jersey Clerk  

E così via ...

e la tabella Places (toponimi con un numero di dipendenti - designazione saggio) è: -

PlaceID PlaceName  Manager  PO Clerk 
1  Alabama   2  0  1 
2  Alaska   1  1  1 
3  Arizona   1  0  2 
4  Arkansas   2  1  1 
5  California  1  1  1 
6  Colorado   1  1  2 
7  Connecticut  0  2  0 

e così via ...

provato con con newid() come come qui sotto e per essere in grado di selezionare i dipendenti con i nomi di luogo RandomPosting,

WITH cteCrossJoin AS (
SELECT e.*, p.PlaceName AS RandomPosting, 
     ROW_NUMBER() OVER(PARTITION BY e.EmpNo ORDER BY NEWID()) AS RowNum 
    FROM Employee e 
     CROSS JOIN Place p 
    WHERE e.Home <> p.PlaceName 
) 
SELECT * 
FROM cteCrossJoin 
WHERE RowNum = 1; 

inoltre ho bisogno di limitare la selezione casuale in base al numero di designazione (nella tabella Places) ... che è assegnare a ciascun Dipendente un PlaceName (da Places) a caso che non sia uguale a CurrentPosting e Home (in Dipendente) e Place Wise designation non superi i numeri indicati.

Grazie in anticipo.

risposta

1

Forse qualcosa di simile:

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) 

Questo dovrebbe cercare di abbinare i dipendenti in base a caso sulla loro designazione scartando stesso currentPosting e la casa, e non assegnare più di quanto specificato in ciascuna colonna per la designazione. Tuttavia, questo potrebbe restituire lo stesso dipendente per più posti, poiché potrebbero corrispondere a più di uno in base a tali criteri.


EDIT: Dopo aver visto i suoi commenti su non avere bisogno di un ad alte prestazioni singola query per risolvere questo problema (che non sono sicuro che è ancora possibile), e dal momento che sembra essere più di un processo di "una tantum" che verrà chiamata, ho scritto il seguente codice utilizzando un cursore e una tabella temporanea per risolvere il problema delle assegnazioni:

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'idea di base è, che itera su i dipendenti, in ordine casuale, e assegna a ciascuno un posto casuale che soddisfa i criteri di diversi messaggi in casa e in corso, nonché il controllo dell'importo assegnato a ciascun luogo per ciascuna designazione per garantire che le posizioni non siano "sovraordinate" per ciascun ruolo.

Questo frammento di codice non modifica i dati in realtà. La dichiarazione finale SELECT restituisce solo i compiti proposti. Tuttavia potresti facilmente modificarlo per apportare modifiche effettive al tuo tavolo Employee di conseguenza.

+0

Grazie per l'aiuto di @Pablo ... come ottenere senza lo stesso dipendente per più posti ... quali criteri aggiuntivi che possiamo mettere - per favore suggerisci ad esempio di ottenere questo senza ripetere lo stesso Emp per Luoghi diversi. – Gaurav

+0

Sto ricevendo una ripetizione indesiderata di mp.PlaceName, ad esempio nella tabella Places "Arizona 1", ovvero Arizona ha bisogno di un solo manager ma questa query restituisce più di 1 manager ad Arozona e la stessa situazione con la maggior parte dei luoghi .. – Gaurav

+0

Ho appena ricevuto testato con il set di dati aggiornato che hai postato sopra, e sembra ancora funzionare bene. Non assegnando mai più di quanto specificato in Places. Sei sicuro che la ripetizione che hai visto non riguardasse un ruolo diverso, come l'OP o l'Impiegato? Inoltre, poiché i confronti qui sono fatti usando le stringhe in Designation, assicurati che tutte le voci di "Manager" siano scritte nello stesso modo, senza spazi, ecc. –

1

Io parto dal presupposto i vincoli sono:

  • Un dipendente non può andare nella stessa posizione s/he è attualmente a.
  • Tutti i siti devono avere almeno un dipendente in ogni categoria, in cui è previsto un dipendente.

L'idea più importante è rendersi conto che non si sta cercando un compito "casuale". Stai cercando una permutazione delle posizioni, a condizione che tutti si spostino altrove.

Ho intenzione di descrivere una risposta per i gestori. Probabilmente vorrai tre query per ogni tipo di dipendente.

L'idea chiave è una tabella ManagerPositions. Questo ha un posto, un numero sequenziale e un numero sequenziale all'interno del luogo. Quanto segue è un esempio:

Araria  1 1 
Araria  2 2 
Arwal  1 3 
Arungabad 1 4 

La query crea questa tabella unendo ad INFORMATION_SCHEMA.COLUMNS con una funzione row_number() per assegnare una sequenza. Questo è un modo rapido e sporco per ottenere una sequenza in SQL Server, ma perfettamente valido fino a quando il numero massimo necessario (ovvero il numero massimo di gestori in una posizione) è inferiore al numero di colonne nel Banca dati. Esistono altri metodi per gestire il caso più generale.

L'idea chiave successiva è di ruotare i luoghi, piuttosto che sceglierli a caso. Questo utilizza idee dall'aritmetica modulo: aggiungi un offset e prendi il resto sul numero totale di posizioni. La query finale assomiglia a questa:

with ManagerPositions as (
    select p.*, 
      row_number() over (order by placerand, posseqnum) as seqnum, 
      nums.posseqnum 
    from (select p.*, newid() as placerand 
      from places p 
     ) p join 
      (select row_number() over (order by (select NULL)) as posseqnum 
      from INFORMATION_SCHEMA.COLUMNS c 
     ) nums 
      on p.Manager <= nums.posseqnum 
    ), 
    managers as (
    select e.*, mp.seqnum 
    from (select e.*, 
       row_number() over (partition by currentposting order by newid() 
            ) as posseqnum 
      from Employees e    
      where e.Designation = 'Manager' 
     ) e join 
     ManagerPositions mp 
     on e.CurrentPosting = mp.PlaceName and 
      e.posseqnum = mp.posseqnum 
) 
select m.*, mp.PlaceId, mp.PlaceName 
from managers m cross join 
    (select max(seqnum) as maxseqnum, max(posseqnum) as maxposseqnum 
     from managerPositions mp 
    ) const join 
    managerPositions mp 
    on (m.seqnum+maxposseqnum+1) % maxseqnum + 1 = mp.seqnum 

Ok, mi rendo conto che questo è complicato. Hai una tabella per ogni posizione manager (non un conteggio come nella tua dichiarazione, avere una riga per ogni posizione è importante). Ci sono due modi per identificare una posizione. Il primo è per luogo e per conteggio all'interno del luogo (posseqnum). Il secondo è un ID incrementale sulle righe.

Trova la posizione corrente nella tabella per ogni gestore. Questo dovrebbe essere unico, perché sto prendendo in considerazione il numero di manager in ogni luogo. Quindi, aggiungi un offset alla posizione e assegna quel posto. Avendo l'offset maggiore del massimo, i gestori sono garantiti per spostarsi in un'altra posizione (tranne in casi limite insoliti in cui una posizione ha più della metà dei gestori).

Se tutte le posizioni attuali del gestore sono occupate, questo garantisce che tutti si spostino nella posizione successiva. Poiché ManagerPositions utilizza un ID casuale per assegnare il seqnum, il "prossimo" posto è casuale, non successivo per id o alfabeticamente.

Questa soluzione ha molti dipendenti che viaggiano insieme nella stessa nuova posizione. È possibile risolvere questo problema cercando valori diversi da "1" nell'espressione (m.seqnum+maxposseqnum+1).

Mi rendo conto che esiste un modo per modificarlo, per evitare la correlazione tra il luogo corrente e il luogo successivo. Questo fa la seguente:

  1. Assegna la seqnum di ManagerPosition casualmente
  2. Compare diversi offset nella tabella, valutare ogni per il numero di volte due posizioni nella tabella, separati da tale correttore, sono gli stessi.
  3. Scegliere l'offset con la valutazione minima (che è preferibilmente 0).
  4. Utilizzare tale offset nella clausola di corrispondenza finale.

Non ho abbastanza tempo per scrivere l'SQL per questo.

+0

grazie per aver aiutato @Gordon ... un problema .. sto ricevendo errori sulle righe "p.Manager <= nums.seqnum"; "e.posseqnum = mp.posseqnum"; "max (posseqnum)" e "m.seqnum + maxposseqnum + 1" come seqnum nome colonna non valido e possswqnum nome colonna invalido. – Gaurav

+0

Nella tabella Luoghi le diverse denominazioni mostrano i numeri, ad esempio la riga della tabella Luoghi- "Araria 2 0 1" mostra che Araria può avere fino a 2 gestori, 0 PO e un solo impiegato. – Gaurav

+0

l'approccio rapido ed efficiente non è desiderato, qualsiasi approccio aiuterà .. – Gaurav

Problemi correlati