2013-06-25 12 views
24

Zajmuję się opracowaniem mojej pierwszej przechowywanej procedury w SQL Server 2008 R2 i potrzebuję porady dotyczącej komunikatu o błędzie.Procedura lub funkcja !!! ma zbyt wiele argumentów określonych

procedura lub funkcja xxx zbyt wiele argumentów określony

które otrzymuję po wykonaniu procedury przechowywanej [dbo].[M_UPDATES] który wywołuje inną procedurę przechowywaną nazwie etl_M_Update_Promo.

Dzwoniąc [dbo].[M_UPDATES] (kod poniżej) poprzez prawym klawiszem myszy i „Wykonaj procedurę przechowywaną” kwerendę, która pojawi się w zapytaniu-okna jest:

USE [Database_Test] 
GO 

DECLARE @return_value int 

EXEC @return_value = [dbo].[M_UPDATES] 

SELECT 'Return Value' = @return_value 

GO 

Wyjście jest

Msg 8144, Poziom 16, Stan 2, Procedura etl_M_Update_Promo, Linia 0
Procedura lub funkcja etl_M_Update_Promo zawiera zbyt wiele argumentów.

PYTANIE: Co oznacza ten komunikat o błędzie dokładnie na myśli, to znaczy gdzie jest zbyt wiele argumentów? Jak je zidentyfikować?

Znalazłem kilka wątków pytających o ten komunikat o błędzie, ale podane kody różniły się od mojego (jeśli nie w innym języku, tak jak i tak C#). Więc żadna z odpowiedzi nie rozwiązała problemu z moim zapytaniem SQL (tj. SPs).

Uwaga: poniżej Podaje kod używany do dwóch SP, ale zmieniłem nazwy baz danych, nazwy tabel i nazwy kolumn. Tak więc, proszę, nie przejmujcie się konwencjami nazewnictwa, to tylko nazwy przykładowe!

Z góry dziękuję za porady i przemyślenia!

(1) kod 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) Kod 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 

Odpowiedz

30

wywołać w funkcji 2 parametrów (@GenId i @Description):

EXEC etl.etl_M_Update_Promo @GenID, @Description 

jednak zostały uznane funkcję wziąć 1 argumentu:

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

SQL Server jest informacją, że [etl_M_Update_Promo] zajmuje tylko 1 parametr (@GenId)

można zmienić procedurę podjąć dwa parametry określając @Description.

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

.... Rest of your code. 
+1

Doskonała! Działa to po usunięciu @Description NVARCHAR (50) z sekcji deklaracji. Dziękujemy za odpowiedź tak szybko i wyraźnie! – user2006697

+1

@Darren Czy istnieje mechanizm ignorowania nieoczekiwanych parametrów? –

+2

@AliAdlavaran dodać im wartość domyślną – CiucaS

1

Ta odpowiedź jest oparta na tytule, a nie na konkretnym przypadku w oryginalnym poście.

Miałem procedurę wstawiania, która powodowała rzucanie tego irytującego błędu i mimo że błąd mówi, "procedura ... miała zbyt wiele argumentów", faktem jest, że procedura NIE miała wystarczającej liczby argumentów.

Tabela miała przyrostową kolumnę id, a ponieważ jest przyrostowa, nie zawracałem sobie głowy dodaniem jej jako zmiennej/argumentu do proc, ale okazało się, że jest potrzebna, więc dodałem ją jako @Id i altówka, jak mówią ... działa.

+0

Miałem to samo. Dodano @ID z default = 0 do procedury, ale obiekt VBA nie używa go w wywołaniu ani nie jest używany w INSERT, ale tak, teraz działa dobrze. Co ciekawe, kiedy uruchomiłem EXEC w SQL, wszystko było w porządku, ale nie było, gdy wywołano mnie z mojego projektu VBA. To musi być błąd! – CarloC

1

Użyj następującego polecenia przed określeniem ich:

cmd.Parameters.Clear() 
0

Oprócz wszystkich udzielonych odpowiedzi tak daleko, innym powodem przyczyną tego wyjątku może się zdarzyć podczas zapisywania danych z listy do bazy danych przy użyciu ADO.NET .

Wielu programistów będzie błędnie używać for pętli lub foreach i pozostawić SqlCommand do wykonania na zewnątrz pętli, aby uniknąć sytuacji, upewnij się, że masz jak ten przykładowy kod, na przykład:

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(); 
     } 
    } 
Powiązane problemy