2012-10-22 2 views
5

Problema:Come faccio a collegare attraverso una tabella temporanea in una stored procedure senza pk

ho bisogno di un ciclo tra i record in una tabella, tirando il numero dei dipendenti e confrontando questo numero dipendente contro un altro tavolo per vedere se sono ancora dipendenti attivi. Se non sono più dipendenti attivi ho bisogno di passare i dati da questa riga in un altro processo memorizzato.

di ricerca:

Googled intorno a un bel po 'e mi rendo conto che non dovrei utilizzare i cursori per questo. Ho fatto però, trovare i seguenti esempi:

  1. http://ask.sqlservercentral.com/questions/7969/loop-through-records-in-a-temporary-table.html
  2. http://eedle.com/2010/11/11/looping-through-records-in-sql-server-stored-procedure/

Tuttavia, sembra che essi utilizzano un pk per scorrere i record. Il numero dei dipendenti può essere la stessa per più recods nel mio scenario

Domande:

  1. è possibile ottenere quello che sto tentando senza cursori?
  2. Se è possibile, come andrei a prendere ogni riga con una colonna non univoca?
+2

si fa a non usare aderire? –

+0

No, eseguo il loop della prima tabella, confronto con la seconda tabella e quando il confronto fallisce, cancello i record dalla prima tabella. In sostanza sto cancellando le ricodifiche dalla prima tabella di dipendenti che non sono più con la compagnia. –

+0

Quali dati stai passando alla stored procedure dalla riga? – podiluska

risposta

6

Dal momento che non ci hai dato una descrizione completa della vostra situazione, non possiamo dare una risposta completa, tuttavia, in generale, è Loops che si vuole evitare in una lingua set-based come SQL e non Cursori(il problema con Cursosr è che essi richiedono i cicli).

Nei tuoi commenti che forniscono un po 'di più informazioni che si desidera "scorrere prima tabella, confrontare a seconda tabella, e quando il confronto non riesce a eliminare i record dalla prima tabella. In essenza sto eliminando recods . dalla prima tabella di dipendenti che non sono più con la società "

Ecco come si può fare questo in SQL:

DELETE From FirstTable 
WHERE FirstTable.EmployeeID NOT IN 
    (
     SELECT SecondTable.EmployeeID 
     FROM SecondTable 
     WHERE SecondTable.Flag = 'Y' 
    ) 

nessun cicli sono necessari ...


Se il problema è allora che si desidera utilizzare un pre-esistente stored procedure per fare la cancellazione, poi ci sono diverse possibilità:

In primo luogo, è possibile estrarre il contenuto della stored procedure e ri-scrittura loro per queste condizioni WHERE precedenti. Capisco che si tratta di duplicazione del codice e che viola gli istinti DRY di alcune persone, tuttavia, capisco che SQL è NON un ambiente di sviluppo orientato agli oggetti e che a volte la duplicazione del codice deve avvenire.

La seconda opzione consisterebbe nel rifattorizzare la stored procedure in modo che potesse accettare un parametro TablePar per i suoi IDimpiedi da eliminare.Tuttavia, questo è complicato e avremmo bisogno di vedere quella stored procedure per consigliarvi.

La terza opzione sarebbe quella di utilizzare l'aggregazione di stringa per costruire SQL dinamico per chiamare la stored procedure per ogni EmployeeID da eliminare in questo modo:

DECLARE @sql As NVarchar(MAX); 
SET  @sql = N''; 

SELECT @sql = @sql + ' 
    EXEC YourProc ''' + CAST(EmployeeID As NVARCHAR(MAX)) + '''; ' 
FROM FirstTable 
WHERE FirstTable.EmployeeID IN 
    (
     SELECT SecondTable.EmployeeID 
     FROM SecondTable 
     WHERE SecondTable.Flag = 'Y' 
    ) 

EXEC(@sql); 

Questo evita sia il Looping ei problemi Cusror, anche se molti non mi piace anche Preferisco questa soluzione io stesso, in gran parte a causa della sua generalità.

+0

Ci scusiamo per la mancanza di informazioni. Il secondo tavolo ha il numero del dipendente lì. Tuttavia, c'è una colonna flag che dice che non sono più attivi. Quindi presumo che funzionerà ancora se imposto la clausola di selezione interna where clausola su "WHERE isActive = 'Y'". –

+0

Sì, la clausola inner where funzionerà. Risponderò al resto nel mio post ... – RBarryYoung

+0

Sta per eseguire l'istruzione select interna per ogni riga in table1? Il motivo per cui lo chiedo è perché non filtra molto le righe restituite e l'istruzione select interna restituirà decine di migliaia di record per ogni record in table1. Non posso ancora testarlo, o ci proverei. Ma posso farlo nella selezione interna: "Dove FirstTable.emp_no = SecondTable.emp_no"? –

3

Questo eliminerà tutti i record dalla tabella dei dati dei dipendenti se non ci sono righe corrispondenti nella tabella dei dipendenti corrente.

sarei suggerisco di sostituire la DELETE FROM con SELECT * FROM e poi quando sei felice di eliminare i risultati cambiano di nuovo a DELETE

DELETE FROM 
    EmployeeDataTable 
WHERE 
    NOT EXISTS 
    (SELECT 
     NULL 
    FROM 
     CurrentEmployees 
    WHERE 
     EmployeeDataTable.EmployeeID = CurrentEmployees.EmployeeID 
    ) 

EDIT: appena visto i suoi commenti sul flag attivo, questo mezzo la query può essere modificata per

DELETE FROM 
    EmployeeDataTable 
WHERE 
    EXISTS 
    (SELECT 
     NULL 
    FROM 
     CurrentEmployees 
    WHERE 
     EmployeeDataTable.EmployeeID = CurrentEmployees.EmployeeID 
     CurrentEmployees.IsActive <> 'Y' 
    ) 
+1

Un altro buon modo per farlo. – RBarryYoung

+0

@RBarryYoung Grazie per il commento. Il fatto che i dipendenti esistano nell'altra tabella ma hanno un flag non da euql a Y, significa che 'NOT EXISTS' può essere cambiato in un' EXISTS' che è meglio. modifico la risposta – Tobsey

+0

Grazie, hai risposto ad un'altra domanda che avevo. :) –

0
  1. sarebbe possibile se si ha il contenuto dal sproc si vogliono chiamare all'interno del vostro cursore e im implementato quella logica all'interno del tuo attuale sproc. A questo punto, dovresti essere in grado di utilizzare la logica basata su set. La sproc che stai chiamando è molto complessa?
  2. Che ne dici di aggiungere una colonna Identity alla tabella temporanea?

A volte i cursori sono la soluzione giusta per una serie di motivi.

2

Farei ciò scorrendo un cursore. È inoltre possibile aggiungere un ID univoco al cursore in modo da sapere su quale riga si sta attualmente.

DECLARE @id uniqueidentifier 
DECLARE @empName VARCHAR(50) 

SELECT newId() AS Id, * 
    INTO #mytemp 
    FROM MyEmployees 
    ORDER BY EmpName 

while EXISTS(SELECT TOP 1 1 FROM #mytemp) 
BEGIN 
    --Get row from cursor to process 
    SELECT TOP 1 @id = Id, @empName = EmpName FROM #mytemp 

    --Do you processing here. Call other stored proc. 

    --Remove processed row from cursor. 
    DELETE FROM #mytemp WHERE Id = @id 
END 
DROP TABLE #mytemp 
+0

Perché questo è stato abbattuto ?, questo loop contruction funziona bene per me. Devo ammettere che la mia stored procedure non è molto veloce, ho usato id per trasferire 45000 record, e ci vogliono circa 4 minuti. Ogni record nella mia temperatura. tabella causa 2 o 3 comandi di aggiornamento nell'area 'elaborazione'. – Michiel

1

Hai pensato di usare il MERGE dichiarazione: http://technet.microsoft.com/en-us/library/bb510625.aspx

Hai clausole:

  1. Quando i dati non corrispondenza tra i due tabella
  2. Quando esiste il dato in origine, ma non nell'obiettivo
  3. Quando i dati esistono nella destinazione, ma non nella fonte

È quindi possibile inserire, aggiornare o eliminare i record a seconda del tipo di corrispondenza. È inoltre possibile generare l'azione dalla corrispondenza a una tabella temporanea per ulteriori operazioni personalizzate.

Per esempio, si può fare:

MERGE INTO Table1 
USING Table2 ON Table1.EmployeeID = Table2.EmployeeID 
WHEN MATCHED 
    THEN UPDATE SET Table1.SomeField = Table2.SomeOtherField 
WHEN NOT MATCHED BY SOURCE 
    THEN DELETE 
WHEN NOT MATCHED BY TARGET 
    THEN Insert (Name, Status) VALUES (EmployeeName, 'Active') 
+0

Ho solo bisogno di cancellare, non inserire o aggiornare. Inoltre sto usando SQL Server 2005 :) –

+0

Ok. È necessario specificare la versione di SQL Server che si sta utilizzando nella domanda se non si utilizza la versione più recente o almeno una non obsoleta da 5 anni ;-) –

+0

Il codice sembra piuttosto semplice. Sfortunatamente non riesco a farlo funzionare su MS SQL Server 2008 R2. Quali versioni di SQL Server supportano questa sintassi? – Michiel