我是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 }
Joel Coehoor.. 6
您应该避免存储过程中的循环.
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表中是唯一的.如果不是这种情况,我需要知道哪些列或列可以唯一地标识表中的行,这样我就可以使用new加入旧记录,并确保关系是1:1.
最后,为简洁起见,省略了错误检查.
您应该避免存储过程中的循环.
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表中是唯一的.如果不是这种情况,我需要知道哪些列或列可以唯一地标识表中的行,这样我就可以使用new加入旧记录,并确保关系是1:1.
最后,为简洁起见,省略了错误检查.
看看WHILE声明:
http://msdn.microsoft.com/en-us/library/aa260676(SQL.80).aspx
但是,根据您要做的事情,可能有一种更好的,基于集合的方式来执行您要执行的操作,并且应该首先考虑这一点.