2013-06-25 28 views
24

私は最初のストアドプロシージャをSQL Server 2008 R2に開発しており、エラーメッセージに関するアドバイスが必要です。手順または機能!!!引数が多すぎます

プロシージャまたは関数xxxはあまりにも多くの引数が、私はetl_M_Update_Promoと呼ばれる別のストアドプロシージャを呼び出すストアドプロシージャ[dbo].[M_UPDATES]を実行した後に取得

を指定しました。

マウスの右クリックし、[実行ストアドプロシージャ 'を介して[dbo].[M_UPDATES](コード下記参照)を呼び出す場合、クエリウィンドウに表示されるクエリは次のとおりです。

USE [Database_Test] 
GO 

DECLARE @return_value int 

EXEC @return_value = [dbo].[M_UPDATES] 

SELECT 'Return Value' = @return_value 

GO 

出力は

です

メッセージ8144、レベル16、状態2、プロシージャetl_M_Update_Promo、行0
プロシージャまたは関数etl_M_Update_Promoに引数が多すぎます。

質問:このエラーメッセージは正確に何を意味するのですか。引数が多すぎますか?それらを特定する方法は?

このエラーメッセージについて質問しているスレッドがいくつか見つかりましたが、提供されるコードはすべて私のものとは異なります(とにかくC#のような別の言語ではない場合)。だから私のSQLクエリ(すなわちSP)の問題を解決した答えはありません。

注:以下では、2つのSPに使用されるコードを示しますが、データベース名、テーブル名、および列名を変更しました。だから、命名規則には気をつけないでください。これらは例の名前に過ぎません!

アドバイスや考えをお寄せいただきありがとうございます。

(1)SP1のコード[DBO]。[M_UPDATES]

USE [Database_Test] 
GO 

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[ M_UPDATES] AS 
declare @GenID bigint 
declare @Description nvarchar(50) 

Set @GenID = SCOPE_IDENTITY() 
Set @Description = 'M Update' 

BEGIN 
EXEC etl.etl_M_Update_Promo @GenID, @Description 
END 

GO 

(2)コードSP2 [etl_M_Update_Promo]

USE [Database_Test] 
GO 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [etl].[etl_M_Update_Promo] 
@GenId bigint = 0 
as 

declare @start datetime = getdate() 
declare @Process varchar (100) = 'Update_Promo' 
declare @SummeryOfTable TABLE (Change varchar (20)) 
declare @Description nvarchar(50) 
declare @ErrorNo int 
, @ErrorMsg varchar (max) 
declare @Inserts int = 0 
, @Updates int = 0 
, @Deleted int = 0 
, @OwnGenId bit = 0 

begin try 


if @GenId = 0 begin 
INSERT INTO Logging.dbo.ETL_Gen (Starttime) 
VALUES (@start) 

SET @GenId = SCOPE_IDENTITY() 
SET @OwnGenId = 1 
end 


MERGE [Database_Test].[dbo].[Promo] AS TARGET 
USING OPENQUERY(M ,'select * from m.PROMO') AS SOURCE 
ON (TARGET.[E] = SOURCE.[E]) 


WHEN MATCHED AND TARGET.[A] <> SOURCE.[A] 
    OR TARGET.[B] <> SOURCE.[B] 
    OR TARGET.[C] <> SOURCE.[C] 
    THEN 
UPDATE SET TARGET.[A] = SOURCE.[A] 
    ,TARGET.[B] = SOURCE.[B] 
    , TARGET.[C] = SOURCE.[c] 

WHEN NOT MATCHED BY TARGET THEN 
INSERT ([E] 
    ,[A] 
    ,[B] 
    ,[C] 
    ,[D] 
    ,[F] 
    ,[G] 
    ,[H] 
    ,[I] 
    ,[J] 
    ,[K] 
    ,[L] 
) 
VALUES (SOURCE.[E] 
    ,SOURCE.[A] 
    ,SOURCE.[B] 
    ,SOURCE.[C] 
    ,SOURCE.[D] 
    ,SOURCE.[F] 
    ,SOURCE.[G] 
    ,SOURCE.[H] 
    ,SOURCE.[I] 
    ,SOURCE.[J] 
    ,SOURCE.[K] 
    ,SOURCE.[L] 
) 

OUTPUT $ACTION INTO @SummeryOfTable; 


with cte as (
SELECT 
Change, 
COUNT(*) AS CountPerChange 
FROM @SummeryOfTable 
GROUP BY Change 
) 

SELECT 
@Inserts = 
    CASE Change 
     WHEN 'INSERT' THEN CountPerChange ELSE @Inserts 
    END, 
@Updates = 
    CASE Change 
     WHEN 'UPDATE' THEN CountPerChange ELSE @Updates 
    END, 
@Deleted = 
    CASE Change 
     WHEN 'DELETE' THEN CountPerChange ELSE @Deleted 
    END 
FROM cte 


INSERT INTO Logging.dbo.ETL_log (GenID, Startdate, Enddate, Process, Message, Inserts, Updates, Deleted,Description) 
VALUES (@GenId, @start, GETDATE(), @Process, 'ETL succeded', @Inserts, @Updates,  @Deleted,@Description) 


if @OwnGenId = 1 
UPDATE Logging.dbo.ETL_Gen 
SET Endtime = GETDATE() 
WHERE ID = @GenId 

end try 
begin catch 

SET @ErrorNo = ERROR_NUMBER() 
SET @ErrorMsg = ERROR_MESSAGE() 

INSERT INTO Logging.dbo.ETL_Log (GenId, Startdate, Enddate, Process, Message, ErrorNo, Description) 
VALUES (@GenId, @start, GETDATE(), @Process, @ErrorMsg, @ErrorNo,@Description) 


end catch 
GO 

答えて

30

ためあなたは2つのパラメータ(@GenIdで関数を呼び出しますそして@description):あなたは1つの引数を取る関数を宣言したが

EXEC etl.etl_M_Update_Promo @GenID, @Description 

ALTER PROCEDURE [etl].[etl_M_Update_Promo] 
    @GenId bigint = 0 

SQL Serverが[etl_M_Update_Promo]が唯一あなたが@Descriptionを指定することにより、2つのパラメータを取るように手順を変更することができます

1つのパラメータ(@GenIdを)取ることを語っています。

ALTER PROCEDURE [etl].[etl_M_Update_Promo] 
    @GenId bigint = 0, 
    @Description NVARCHAR(50) 
AS 

.... Rest of your code. 
+1

エクセレント:

多くの開発者が誤ってそれはあなたが例えば、このコードサンプルのように持っていることを確認してくださいforループまたはforeachを使用して避けるために、ループの外で実行するSqlCommandを残すだろう!これは、宣言セクションから@Description NVARCHAR(50)を削除した後に機能します。とても早く応答してくれてありがとう! – user2006697

+1

@Darren予期しないパラメータを無視するメカニズムはありますか? –

+2

@AliAdlavaranそれらにデフォルト値を加えてください – CiucaS

1

この回答はタイトルに基づいており、元の投稿の特定の例ではありません。

私はこの厄介なエラーを投げつけた挿入手順を持っていましたが、 "手順....引数が多すぎます"というエラーが表示されても、手順には十分な引数がありませんでした。

テーブルにはインクリメンタルIDカラムがあり、インクリメンタルなので、変数/引数として追加するのは面倒でしたが、必要であることが判明したので、@Idとして追加しました彼らが言うようにビオラと...それは動作します。

+0

私は同じものを持っていました。プロシージャにデフォルト= 0の@IDを追加しましたが、VBAオブジェクトは呼び出し時にそれを使用していないか、INSERTで使用されていませんが、現在は正常に動作しています。面白いことに、SQLでEXECを実行したときには問題ありませんでしたが、VBAプロジェクトから呼び出されたときは問題ありませんでした。バグでなければならない! – CarloC

1

それらを定義する前に、次のコマンドを使用します

cmd.Parameters.Clear() 
0

これまでに提供されるすべての回答に加えて、あなたはADO.Netを使用してデータベースにリストからデータを保存しているときに、この例外を発生させたことは起こることができるため、別の理由を。

public static void Save(List<myClass> listMyClass) 
    { 
     using (var Scope = new System.Transactions.TransactionScope()) 
     { 
      if (listMyClass.Count > 0) 
      { 
       for (int i = 0; i < listMyClass.Count; i++) 
       { 
        SqlCommand cmd = new SqlCommand("dbo.SP_SaveChanges", myConnection); 
        cmd.CommandType = CommandType.StoredProcedure; 
        cmd.Parameters.Clear(); 

        cmd.Parameters.AddWithValue("@ID", listMyClass[i].ID); 
        cmd.Parameters.AddWithValue("@FirstName", listMyClass[i].FirstName); 
        cmd.Parameters.AddWithValue("@LastName", listMyClass[i].LastName); 

        try 
        { 
         myConnection.Open(); 
         cmd.ExecuteNonQuery(); 
        } 
        catch (SqlException sqe) 
        { 
         throw new Exception(sqe.Message); 
        } 
        catch (Exception ex) 
        { 
         throw new Exception(ex.Message); 
        } 
        finally 
        { 
         myConnection.Close(); 
        } 
       } 
      } 
      else 
      { 
       throw new Exception("List is empty"); 
      } 

      Scope.Complete(); 
     } 
    } 
関連する問題