質問

私は 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 ループの条件と一致します。したがって、ループは 1 回だけ実行される (1 つのレコードが返される) か、挿入によって反復ごとに複数の新しいレコードが挿入されます (はい、insert ステートメントは一度に複数のレコードを追加できます)。また、複数のレコードを追加している場合、なぜ最後の挿入によって作成された ID のみを取得するのでしょうか?

とはいえ、何かを示すには十分理解していると思います。見積書のコピーを作成しているだけのようです。また、@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

ただし、あなたがやろうとしていることに応じて、おそらくあなたがやろうとしていることを行うためのより良い、セットベースの方法があり、最初にそれを考慮する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top