web-dev-qa-db-fra.com

Procédure ou fonction !!! a trop d'arguments spécifiés

Je développe ma toute première procédure stockée dans SQL Server 2008 R2 et j'ai besoin de conseils concernant le message d'erreur.

Procédure ou fonction xxx trop d'arguments spécifiés

que je reçois après avoir exécuté la procédure stockée [dbo].[M_UPDATES] qui appelle une autre procédure stockée appelée etl_M_Update_Promo.

Lorsque vous appelez [dbo].[M_UPDATES] (voir ci-dessous) par un clic droit et par "Exécuter la procédure stockée", la requête qui apparaît dans la fenêtre de requête est la suivante:

USE [Database_Test]
GO

DECLARE @return_value int

EXEC    @return_value = [dbo].[M_UPDATES]

SELECT  'Return Value' = @return_value

GO

La sortie est 

Msg 8144, Niveau 16, Etat 2, Procédure etl_M_Update_Promo, Ligne 0
La procédure ou la fonction etl_M_Update_Promo a trop d'arguments spécifiés.

QUESTION: Que signifie exactement ce message d'erreur, c’est-à-dire où sont trop d’arguments? Comment les identifier?

J'ai trouvé plusieurs discussions sur ce message d'erreur, mais les codes fournis étaient tous différents des miens (si ce n'est dans une autre langue comme C# de toute façon). Donc, aucune des réponses n'a résolu le problème de ma requête SQL (c'est-à-dire SP).

Remarque: ci-dessous, je fournis le code utilisé pour les deux SP, mais j'ai changé les noms de base de données, les noms de table et les noms de colonne. Donc, ne vous inquiétez pas des conventions de nommage, ce ne sont que des exemples de noms!

Merci d'avance pour vos conseils et réflexions!

(1) Code pour 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) Code pour 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
user2006697

Vous appelez la fonction avec 2 paramètres (@GenId et @Description):

EXEC etl.etl_M_Update_Promo @GenID, @Description

Cependant, vous avez déclaré que la fonction prenait 1 argument:

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

SQL Server vous dit que [etl_M_Update_Promo] prend seulement 1 paramètre (@GenId)

Vous pouvez modifier la procédure pour prendre deux paramètres en spécifiant @Description.

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

.... Rest of your code.
35
Darren

Cette réponse est basée sur le titre et non sur le cas particulier de l'article d'origine. 

J'avais une procédure d'insertion qui renvoyait cette erreur ennuyeuse, et même si l'erreur dit, "procédure .... a trop d'arguments spécifiés", le fait est que la procédure N'A PAS assez d'arguments.

La table avait une colonne d’identification incrémentielle, et comme elle est incrémentale, je n’ai pas pris la peine de l’ajouter en tant que variable/argument au proc, mais il s’est avéré qu’elle était nécessaire, je l’ai donc ajoutée sous la forme @Id et alto dis ... ça marche.

2
usefulBee

Utilisez la commande suivante avant de les définir:

cmd.Parameters.Clear()
2
FEOL

Pour ceux qui pourraient avoir le même problème que moi, j'ai eu cette erreur lorsque la base de données que j'utilisais était en fait master , et non la base de données à utiliser. 

Il suffit de mettre use [DBName] en haut de votre script ou de modifier manuellement la base de données utilisée dans l'interface graphique de SQL Server Management Studio.

0
Ray Lionfang

En plus de toutes les réponses fournies jusqu'à présent, une autre raison pouvant être à l'origine de cette exception peut se produire lorsque vous sauvegardez des données d'une liste dans une base de données à l'aide de ADO.Net.

De nombreux développeurs vont utiliser par erreur for loop ou foreach et laisser le SqlCommand s'exécuter en dehors de la boucle, pour éviter cela, assurez-vous que vous avez comme cet exemple de code:

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();
        }
    }
0
Ashraf Abusada