sql2000 en boucle dans une procédure stockée
-
03-07-2019 - |
Question
Je suis très novice en SQL, je peux travailler avec les instructions de base assez facilement, mais je n’ai pas encore compris les boucles.
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
}
La solution
Vous devez éviter les boucles dans les procédures stockées.
Sql est un langage déclaratif, plutôt que les langages impératifs auxquels vous êtes le plus habitué. Presque tout ce que vous voulez faire avec une boucle doit être effectué en tant qu'opération basée sur un ensemble ou en code client. Il existe bien sûr des exceptions, mais pas autant que vous le pensez.
Voir ceci:
Pourquoi est-il si difficile de faire une boucle dans T-SQL
Vous avez demandé comment procéder à l'aide de méthodes basées sur des ensembles. Je ferai de mon mieux, mais il y a un bogue dans votre code qui empêche de bien le lire. La condition de la première instruction INSERT correspond à la condition de la boucle FOREACH. Ainsi, la boucle ne sera exécutée qu'une seule fois (un enregistrement y est retourné) ou votre insertion insère plusieurs nouveaux enregistrements par itération (oui, les instructions d'insertion peuvent ajouter plusieurs enregistrements à la fois). Et s’il ajoute plusieurs enregistrements, pourquoi n’obtenez-vous que l’identité créée par la dernière insertion?
Cela dit, je pense que je le comprends assez bien pour vous montrer quelque chose. On dirait que vous ne faites que copier une estimation. De plus, vous n'expliquez pas d'où provient la valeur @NewEstimateID. S’il existe une table parente, qu’il en soit ainsi, mais il serait utile de connaître.
/* 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
Le code ci-dessus suppose que ServiceID + EstimateID est unique dans la table EstimateJobHeader. Si ce n'est pas le cas, j'ai besoin de savoir quelle colonne ou quelles colonnes identifient de manière unique les lignes de la table, de manière à pouvoir joindre l'ancien enregistrement au nouvel enregistrement et être certain que la relation est 1: 1.
Enfin, la vérification des erreurs a été omise par souci de brièveté.
Autres conseils
Jetez un coup d’œil à l’instruction WHILE:
http://msdn.microsoft.com/en -us / library / aa260676 (SQL.80) .aspx
Cependant, selon ce que vous essayez de faire, il existe probablement une meilleure façon, basée sur les paramètres, de faire ce que vous essayez de faire, et vous devriez en tenir compte en premier.