none
ストアドプロシージャの呼び出し方 RRS feed

  • 質問

  •    ストアドプロシージャの呼び出し方で質問です
      環境はVS2008 XPSP3です。

     細かいソースは割愛させていただきます。

                Table = new DataTable();
                Cn = new SqlConnection("接続文字列");
                SQLCm = Cn.CreateCommand();
                Adapter = new SqlDataAdapter(SQLCm);

                SQLCm.CommandType = System.Data.CommandType.StoredProcedure;

                SQLCm.CommandText = "ストアド名";

                Adapter.Fill(Table);



        SQLCm.CommandType = System.Data.CommandType.StoredProcedure;
        この記述を抜かしても実際にストアドを呼び出せるのですが、内部的に
        何か変換をおこなっているのでしょうか?

     


                

    2009年3月2日 2:45

回答

  • 少し試してみました。SqlCommandの問題ではなく、SQL Serverにおける処理の結果のようです。
    SqlCommandですが、CommnadTypeをTextとした場合、SQL Serverに発行されるコマンドは"TEST"です。これに対して、CommandTypeをStoredProcedureにした場合、"EXEC TEST"と発行されます。
    さて、SQL Server側ですが、最初のコマンドがストアドプロシージャ名である場合、EXECが省略できます。したがって、"TEST"というコマンドを受けとった場合、SQL Serverは"TEST"というストアドプロシージャを実行することになります。なぜSQL Serverは"TEST"をSQL文だと思わないかと言えば、"TEST"で始まるSQL文は無いからでしょう。これは次の簡単なステートメントを実行してみるとわかります。
    "select"
    これを実行すると、「'select"付近に不適切な構文があります。」となりますが、
    "selects"
    を実行すると、「ストアドプロシージャ'selects'は見つかりませんでした。」となります。

    最後に残った問題として、なぜパラメータ付きのストアドプロシージャだとうまくいかないのでしょうか? それはCommnadTypeがTextであり、かつ、パラメータがある場合は、sp_executesplによってSQL文が発行されるからです。具体的には、
    exec sp_executesql N'TEST',N'@id int',@id=1
    となります。TESTというSQL文を実行しようとしますから、当然失敗します。
    ちなみにCommandTypeをStoredProcedureにした場合は、
    exec TEST @id=1
    が発行され、正しくストアドプロシージャが呼び出されます。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年3月2日 7:17
    モデレータ
  • CommandTypeのデフォルトはTextであり、この状態ではCommnadTextに設定した文字列はSQL文だと解釈し、自動的にストアドプロシージャ名だと推測してくれることは無いと思います。私の方で簡単な実験をしましたが、やはりSQL文としか解釈してくれませんでした。
    確認ですが、Adapter.Fill(Table);にブレークポイントを設定し、その時点でCommandTypeはどのようになっていますでしょうか?
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク sk7474 2009年3月9日 8:55
    2009年3月2日 5:21
    モデレータ

すべての返信

  • CommandTypeのデフォルトはTextであり、この状態ではCommnadTextに設定した文字列はSQL文だと解釈し、自動的にストアドプロシージャ名だと推測してくれることは無いと思います。私の方で簡単な実験をしましたが、やはりSQL文としか解釈してくれませんでした。
    確認ですが、Adapter.Fill(Table);にブレークポイントを設定し、その時点でCommandTypeはどのようになっていますでしょうか?
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク sk7474 2009年3月9日 8:55
    2009年3月2日 5:21
    モデレータ
  • 書き込みありがとうございました。

    私もあまり実験をせずに書き込みをしてしまいました。

    いろいろと試したところ、単純なSELECTクエリ(パラメータなどを指定させない)で
    下記のコードを実行したところデータが取得できます。

    パラメータなどを指定すると実行はできませんでした。
    下記がNorthwindで実行したコードです。

             SqlConnection Cn;
             SqlCommand SQLCm;
             SqlDataAdapter Adapter;
             DataTable DataTable = new DataTable();

               Cn = new SqlConnection("Data Source="サーバー名";Initial Catalog=Northwind;User ID=ID名");
               SQLCm = Cn.CreateCommand();
               Adapter = new SqlDataAdapter(SQLCm);


               SQLCm.CommandText = "TEST";

               Adapter.Fill(DataTable);

     ストアドプロシージャは下記で作成しました。

    -- ================================================
    -- Template generated from Template Explorer using:
    -- Create Procedure (New Menu).SQL
    --
    -- Use the Specify Values for Template Parameters
    -- command (Ctrl-Shift-M) to fill in the parameter
    -- values below.
    --
    -- This block of comments will not be included in
    -- the definition of the procedure.
    -- ================================================
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:  <Author,,Name>
    -- Create date: <Create Date,,>
    -- Description: <Description,,>
    -- =============================================
    CREATE PROCEDURE TEST
     -- Add the parameters for the stored procedure here

    AS
    BEGIN
     -- SET NOCOUNT ON added to prevent extra result sets from
     -- interfering with SELECT statements.
     SET NOCOUNT ON;

        -- Insert statements for procedure here
     SELECT                  CategoryID, CategoryName
    FROM                     Categories
    END
    GO

    ちなみにAdapter.Fill(Table);にブレークポイントを設定し、その時点でCommandTypeはSystem.Data.CommandType.Text
    になっていました。

    いったいどうしてなのでしょうかね?

    2009年3月2日 6:04
  • 少し試してみました。SqlCommandの問題ではなく、SQL Serverにおける処理の結果のようです。
    SqlCommandですが、CommnadTypeをTextとした場合、SQL Serverに発行されるコマンドは"TEST"です。これに対して、CommandTypeをStoredProcedureにした場合、"EXEC TEST"と発行されます。
    さて、SQL Server側ですが、最初のコマンドがストアドプロシージャ名である場合、EXECが省略できます。したがって、"TEST"というコマンドを受けとった場合、SQL Serverは"TEST"というストアドプロシージャを実行することになります。なぜSQL Serverは"TEST"をSQL文だと思わないかと言えば、"TEST"で始まるSQL文は無いからでしょう。これは次の簡単なステートメントを実行してみるとわかります。
    "select"
    これを実行すると、「'select"付近に不適切な構文があります。」となりますが、
    "selects"
    を実行すると、「ストアドプロシージャ'selects'は見つかりませんでした。」となります。

    最後に残った問題として、なぜパラメータ付きのストアドプロシージャだとうまくいかないのでしょうか? それはCommnadTypeがTextであり、かつ、パラメータがある場合は、sp_executesplによってSQL文が発行されるからです。具体的には、
    exec sp_executesql N'TEST',N'@id int',@id=1
    となります。TESTというSQL文を実行しようとしますから、当然失敗します。
    ちなみにCommandTypeをStoredProcedureにした場合は、
    exec TEST @id=1
    が発行され、正しくストアドプロシージャが呼び出されます。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年3月2日 7:17
    モデレータ
  •  丁寧な解説ありがとうございました。

    疑問が解決いたしまして、スッキリしました^^

    2009年3月2日 9:09
  • こんにちは。中川俊輔です。

    trapemiyaさん、回答ありがとうございます。

    さとさとさん、フォーラムのご利用ありがとうございます。
    有用な情報と思われたため、trapemiyaさんの回答へ回答マークをつけさせていただきました。

    今後ともフォーラムをよろしくお願いします。
    それでは!
    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年3月9日 8:57