Цикл sql2000 в хранимой процедуре
-
03-07-2019 - |
Вопрос
Я новичок в SQL. Я довольно легко могу работать с базовыми операторами, но еще не разобрался с циклами.
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
}
Решение
Вам следует избегать циклов в хранимых процедурах.
Sql — это декларативный язык, а не привычные вам императивные языки.Почти все, что вы хотите сделать с помощью цикла, должно выполняться либо как операция на основе множества, либо в клиентском коде.Исключения, конечно, есть, но не так много, как вам кажется.
Видеть это:
Почему так сложно выполнить цикл в T-SQL
Вы спросили, как это сделать, используя методы, основанные на множествах.Я сделаю все возможное, но в начале вашего кода есть ошибка, из-за которой сложно убедиться, что я его правильно читаю.Условие первого оператора INSERT соответствует условию цикла FOREACH.Таким образом, либо цикл будет выполняться только один раз (там возвращается одна запись), либо ваша вставка вставляет несколько новых записей за итерацию (да, операторы вставки могут добавлять более одной записи за раз).А если добавляется несколько записей, почему вы получаете только идентификатор, созданный последней вставкой?
Тем не менее, я думаю, что понимаю это достаточно хорошо, чтобы показать вам кое-что.Похоже, вы просто делаете копию сметы.Вы также не объясняете, откуда берется значение @NewEstimateID.Если есть родительская таблица, пусть будет так, но было бы полезно узнать о ней.
/* 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
В приведенном выше коде предполагается, что ServiceID+EstimateID уникальны в таблице EstimateJobHeader.Если это не так, мне нужно знать, какой столбец или столбцы однозначно идентифицируют строки в таблице, чтобы я мог соединить старую запись с новой и быть уверенным, что отношение составляет 1:1.
Наконец, для краткости опущена проверка ошибок.
Другие советы
Взгляните на оператор WHILE:
http://msdn.microsoft.com/en-us/library/aa260676(SQL.80).aspx
Однако, в зависимости от того, что вы пытаетесь сделать, вероятно, существует лучший, основанный на наборах способ сделать то, что вы пытаетесь сделать, и его следует рассмотреть в первую очередь.