SQL Server 2008 R2
で最初のストアドプロシージャを開発していますが、エラーメッセージに関するアドバイスが必要です。
プロシージャまたは関数xxxの引数が多すぎます
[dbo].[M_UPDATES]
という別のストアドプロシージャを呼び出すストアドプロシージャetl_M_Update_Promo
を実行した後に取得します。
マウスの右クリックおよび「ストアドプロシージャの実行」で[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に指定された引数が多すぎます。
QUESTION:このエラーメッセージは正確に何を意味しますか?それらを識別する方法は?
このエラーメッセージについて尋ねるスレッドがいくつか見つかりましたが、提供されるコードはすべて私のものとは異なります(とにかく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
2つのパラメーター(@GenIdおよび@Description)で関数を呼び出します。
EXEC etl.etl_M_Update_Promo @GenID, @Description
ただし、1つの引数を取るように関数を宣言しています。
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
@GenId bigint = 0
SQL Serverは、[etl_M_Update_Promo]
が1つのパラメーター(@GenId
)しか受け取らないことを伝えています
@Description
を指定することにより、2つのパラメーターを取るようにプロシージャーを変更できます。
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
@GenId bigint = 0,
@Description NVARCHAR(50)
AS
.... Rest of your code.
この回答は、元の投稿の特定のケースではなく、タイトルに基づいています。
この厄介なエラーをスローし続ける挿入プロシージャがあり、エラーが「プロシージャ....指定された引数が多すぎます」と言っても、実際にはプロシージャに十分な引数がありませんでした。
テーブルにはインクリメンタルID列があり、インクリメンタルであるため、変数/引数としてプロシージャに追加することはありませんでしたが、必要であることが判明したので、@ Idとビオラとしてそれらを追加しました言う...それは動作します。
定義する前に次のコマンドを使用します。
cmd.Parameters.Clear()
私と同じ問題を抱えているかもしれない人のために、私が使用しているDBが実際にはmasterであり、使用すべきDBではないときにこのエラーを受け取りました。
use [DBName]
をスクリプトの先頭に置くか、SQL Server Management Studio GUIで使用中のDBを手動で変更します。
これまでに提供されたすべての回答に加えて、ADO.Netを使用してリストからデータベースにデータを保存しているときに、この例外を引き起こす別の理由が発生する可能性があります。
多くの開発者は、誤ってfor
ループまたはforeach
を使用し、SqlCommand
をループの外側で実行するために、このコードサンプルのようにすることを避けるために、ループの外側で実行します。
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();
}
}