Ciclo sql2000 in una procedura memorizzata
-
03-07-2019 - |
Domanda
Sono molto nuovo in SQL, posso lavorare con le istruzioni di base abbastanza facilmente ma non ho ancora capito i cicli.
Foreach(JobHeaderID AS @OldJobHeaderID in dbo.EstimateJobHeader WHERE EstimateID=@OldEstimateID)
{
INSERT EstimateJobHeader (ServiceID,EstimateID)
SELECT ServiceID, @NewEstimateID
FROM EstimateJobHeader
WHERE EstimateID=@OldEstimateID;
SELECT @err = @@error
IF @err <> 0
BEGIN
ROLLBACK TRANSACTION
SET @RETURN_VALUE = 4
RETURN 4
END
SET @NewJobHeaderID = CAST(SCOPE_IDENTITY() AS INT)
SELECT @err = @@error
IF @err <> 0
BEGIN
ROLLBACK TRANSACTION
SET @RETURN_VALUE = 3
RETURN 3
END
INSERT EstimateDetail (JobHeaderID, OtherCols)
SELECT (@NewJobHeaderID,OtherCols)
FROM EstimateDetail
WHERE JobHeaderID=@OldJobHeaderID
SELECT @err = @@error
IF @err <> 0
BEGIN
ROLLBACK TRANSACTION
SET @RETURN_VALUE = 3
RETURN 3
END
INSERT EstimateJobDetail (JobHeaderID, OtherCols)
SELECT (@NewJobHeaderID, OtherCols)
FROM EstimateJobDetail
WHERE JobHeaderID=@OldJobHeaderID
SELECT @err = @@error
IF @err <> 0
BEGIN
ROLLBACK TRANSACTION
SET @RETURN_VALUE = 3
RETURN 3
END
}
Soluzione
Dovresti evitare i loop nelle procedure memorizzate.
SQL è un linguaggio dichiarativo, piuttosto che le lingue imperative a cui sei più abituato. Quasi tutto ciò che si desidera fare con un ciclo deve essere eseguito come operazione basata su set o nel codice client. Ci sono, ovviamente, eccezioni, ma non quante ne pensi.
Vedi questo:
Perché è così difficile fare un loop in T-SQL
Hai chiesto come farlo utilizzando metodi basati su set. Farò del mio meglio, ma c'è un bug all'inizio del tuo codice che rende difficile essere sicuro di leggerlo bene. La condizione sulla prima istruzione INSERT corrisponde alla condizione sul ciclo FOREACH. Quindi o il ciclo verrà eseguito solo una volta (un record restituito lì) oppure l'inserto sta inserendo diversi nuovi record per iterazione (sì, le istruzioni insert possono aggiungere più di un record alla volta). E se sta aggiungendo diversi record, perché ottieni solo l'identità creata dall'ultimo inserto?
Detto questo, penso di averlo capito abbastanza bene da mostrarti qualcosa. Sembra che tu stia solo facendo una copia di un preventivo. Inoltre, non spieghi da dove proviene il valore @NewEstimateID. Se esiste una tabella padre, così sia, ma sarebbe utile conoscerla.
/* Where'd @NewEstimateID come from? */
/* If there are several records in EstimateJobHeader with @OldEstimateID,
* this will insert one new record for each of them */
INSERT EstimateJobHeader (ServiceID,EstimateID)
SELECT ServiceID, @NewEstimateID
FROM EstimateJobHeader
WHERE EstimateID= @OldEstimateID
/* Copy EstimateDetail records from old estimate to new estimate */
INSERT EstimateDetail (JobHeaderID, OtherCols)
SELECT (new.JobHeaderID,ed.OtherCols)
FROM EstimateJobHeader new
INNER JOIN EstimateJobHeader old ON old.EstimateID= @OldEstimateID
AND new.EstimateID= @NewEstimateID AND old.ServiceID=new.ServiceID
INNER JOIN EstimateDetail ed ON ed.JobHeaderID= old.JobHeaderID
/* Copy EstimateJobDetail records from old estimate to new estimate */
INSERT EstimateJobDetail (JobHeaderID, OtherCols)
SELECT (new.JobHeaderID,ed.OtherCols)
FROM EstimateJobHeader new
INNER JOIN EstimateJobHeader old ON old.EstimateID= @OldEstimateID
AND new.EstimateID= @NewEstimateID AND old.ServiceID=new.ServiceID
INNER JOIN EstimateJobDetail ejd ON ejd.JobHeaderID= old.JobHeaderID
Il codice sopra riportato presuppone che ServiceID + StimaID sia univoco nella tabella StimaJobHeader. In caso contrario, devo sapere quale colonna o colonne identificano in modo univoco le righe nella tabella, in modo da poter unire il vecchio record con il nuovo ed essere sicuro che la relazione sia 1: 1.
Infine, il controllo degli errori è stato omesso per brevità.
Altri suggerimenti
Dai un'occhiata all'istruzione WHILE:
http://msdn.microsoft.com/en -us / library / aa260676 (SQL.80) .aspx
Tuttavia, a seconda di ciò che si sta tentando di fare, esiste probabilmente un modo migliore e basato su set per fare ciò che si sta tentando di fare, che è necessario considerare prima.