I am developing my very first stored procedure in SQL Server 2008 and need advice concerning the errors message.
Procedure or function xxx too many arguments specified
which I get after executing the stored procedure [dbo].[M_UPDATES] that calls another stored procedure called etl_M_Update_Promo.
When calling [dbo].[M_UPDATES] (code see below) via right-mouse-click and ‘Execute stored procedure’ the query that appears in the query-window is:
USE [Database_Test]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[M_UPDATES]
SELECT 'Return Value' = #return_value
GO
The output is
Msg 8144, Level 16, State 2, Procedure etl_M_Update_Promo, Line 0
Procedure or function etl_M_Update_Promo has too many arguments specified.
QUESTION: What does this error message exactly mean, i.e. where are too many arguments? How to identify them?
I found several threads asking about this error message, but the codes provided were all different to mine (if not in another language like C# anyway). So none of the answers solved the problem of my SQL query (i.e. SPs).
Note: below I provide the code used for the two SPs, but I changed the database names, table names and column names. So, please, don’t be concerned about naming conventions, these are only example names!
(1) Code for 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 for 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
You invoke the function with 2 parameters (#GenId and #Description):
EXEC etl.etl_M_Update_Promo #GenID, #Description
However you have declared the function to take 1 argument:
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
#GenId bigint = 0
SQL Server is telling you that [etl_M_Update_Promo] only takes 1 parameter (#GenId)
You can alter the procedure to take two parameters by specifying #Description.
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
#GenId bigint = 0,
#Description NVARCHAR(50)
AS
.... Rest of your code.
Use the following command before defining them:
cmd.Parameters.Clear()
This answer is based on the title and not the specific case in the original post.
I had an insert procedure that kept throwing this annoying error, and even though the error says, "procedure....has too many arguments specified," the fact is that the procedure did NOT have enough arguments.
The table had an incremental id column, and since it is incremental, I did not bother to add it as a variable/argument to the proc, but it turned out that it is needed, so I added it as #Id and viola like they say...it works.
For those who might have the same problem as me, I got this error when the DB I was using was actually master, and not the DB I should have been using.
Just put use [DBName] on the top of your script, or manually change the DB in use in the SQL Server Management Studio GUI.
Yet another cause of this error is when you are calling the stored procedure from code, and the parameter type in code does not match the type on the stored procedure.
I feel ashamed for even having to post this, but it might help someone in the future. Make sure you don't have a typo in your function call!
I kept getting this error trying to call a function and couldn't figure out why. My function and call had the same number of arguments (or so I thought).
Here's my function call:
SELECT FORMAT_NAME(A.LASTNAME, A.FIRSTNAME, A,MIDDLENAME)
It's easier to see in Stack Overflow, but it wasn't so obvious in SSMS that I had a comma in place of a period for A.MIDDLENAME.
SELECT FORMAT_NAME(A.LASTNAME, A.FIRSTNAME, A.MIDDLENAME)
Simple user error.
In addition to all the answers provided so far, another reason for causing this exception can happen when you are saving data from list to database using ADO.Net.
Many developers will mistakenly use for loop or foreach and leave the SqlCommand to execute outside the loop, to avoid that make sure that you have like this code sample for example:
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();
}
}
You either have to double check the Parameters on both side (StoredProcedure And Code):
Make Sure they are the same on both ends regarding to the number of them.
Make Sure you have NOT changed your StoredProcedure code and forgot to Execute it, nothing bad happens if you hit F5 to make sure have all the changes committed and saved.
Make Sure you you have the same naming convention on both sides (Not Likely to be the cause but it worth a shot).
Hey all I am trying to figure out how to go about this. I am wanting to send a parameter that is the name of my table to a query in my C# program. I've read that this is not possible and they suggested that you make a stored procedure to do this.
So this is my code so far:
CREATE PROCEDURE _tmpSP
#TableName NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT TOP 1 HelpMsg FROM ' + QUOTENAME(#TableName)
EXECUTE sp_executesql #Sql
DROP PROCEDURE [_tmpSP]
END
When I execute that in Server Management Studio it creates the SP but never executes that store procedure nor deletes it.
When I run that SP in Server Management Studio (right-clicking on it under Programmability>dbo._tmpSP and choosing Execute Stored Procedure) and give it the table name, it populates and then deletes the SP. This is the end result I want without having to make 2 query's.
The SQL query for when the SP runs is this (tHelp being the table name):
USE [TTool]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[_tmpSP]
#TableName = N'tHelp'
SELECT 'Return Value' = #return_value
GO
I get the returned help message and also returned value 0.
How can I modify this SP in order to do that?
Just do this, forget stored procedures:
EXECUTE sp_executesql 'SELECT TOP 1 HelpMsg FROM '+QUOTENAME(#TableName)
Dirty C#...
string qry = string.Format("SELECT TOP 1 HelpMSG FROM {0}", myTableName.Replace("'", "''"));
cmd = conn.CreateCommand();
cmd.CommandText = qry;
string helpMsg = conn.ExecuteScalar();
Where conn is an instance of System.Data.SqlClient.SqlConnection
I agree with #SsJVasto. If you still need your query not be hard coded in the C# program you can use an xml and keep the query in it. And fetch the xml and execute the query. I guess you would like to handle some dynamic stuff.
There is no point in doing this because there is quite complicated and also incurs the overhead of creating and dropping of the stored procedure. If you have a dynamic query that deals with some dynamic elements that cannot be pushed as parameters, you can construct the query string:
var query = $"SELECT TOP 1 col FROM {tableName}";
However, you must take care to avoid SQL injection if tableName is constructed based on user input. This question and its answers deal with this problem:
DbConnection connection = GetMyConnection();
DbProviderFactory factory = DbProviderFactories.GetFactory(connection);
DbCommandBuilder commandBuilder = factory.CreateCommandBuilder();
var tableName commandBuilder.QuoteIdentifier(rawTableName);
If "normal" (non table name) parameters are needed, pass them as usual within the query. E.g. #param1, #param2
You need create another SP to apply your logic. First let's see your SP:
CREATE PROCEDURE [_tmpSP]
#TableName NVARCHAR(128)
AS
BEGIN
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT TOP 1 HelpMsg FROM ' + #TableName
EXEC(#Sql)
END
Then create another SP only if you need to drop the first one after return the result. The logic will be :
Create procedure auto_delete
#NewTableName
as
begin
EXEC _tmpSP #TableName = #NewTableName
Drop procedure [_tmpSP]
End
In C# (I assume you are using the 2nd SP above):
Your code could be like this:
..
using System.Data.SqlClient;
..
string a = YourTableName;
using (SqlConnection sqlCon = new SqlConnection(YourDatabaseConnection))
{
sqlCon.Open()
using (SqlCommand sqlCmd = sqlCon.CreateCommand())
{
sqlCmd.CommandText = "auto_delete";
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd.Parameters.Add(new SqlParameter("NewTableName", a));
sqlCmd.ExecuteNonQuery();
}
sqlCon.Close();
}
I have a problem with a procedure that I'm developing in MySQL, this is my first time. A few months ago I made a small CRUD (select, insert, update) in MSSQL, and only sends the required data.
create procedure sp_Bodegas (#Opcion varchar(10), #CodBodega int = null, #NomBodega varchar(75) = null, #DirBodega varchar(150) = null, #EstBodega bit = null)
as
begin
set nocount on
if (#Opcion='SELECT')
begin
select cod_Bodega as CodBodega, nom_Bodega as NomBodega, dir_Bodega as DirBodega, est_Bodega as EstBodega from inv_Bodegas
end
if (#Opcion='INSERT')
begin
insert into inv_Bodegas (cod_Bodega, nom_Bodega, dir_Bodega, est_Bodega) values (#CodBodega, #NomBodega, #DirBodega, #EstBodega)
end
if (#Opcion='UPDATE')
begin
update inv_Bodegas set nom_Bodega = #NomBodega, dir_Bodega = #DirBodega where cod_Bodega = #CodBodega
end
set nocount off
end;
But a few days ago I started to work with MySQL and try to do the same procedure but this can not use variables such as '#NomBodega = Null' for not sending any data required option. then create input variables to receive the data, but now there are many parameters that have to send every time you run the procedure.
create procedure sp_Bodegas (in Opcion varchar(10), in CodBodega int, in NomBodega varchar(75), in DirBodega varchar(150), in EstBodega bit)
begin
if Opcion = 'SELECT' then
select cod_Bodega as CodBodega, nom_Bodega as NomBodega, dir_Bodega as DirBodega, est_Bodega as EstBodega from inv_Bodegas;
end if;
if Opcion = 'INSERT' then
insert into inv_Bodegas (cod_Bodega, nom_Bodega, dir_Bodega, est_Bodega) values (#CodBodega, #NomBodega, #DirBodega, #EstBodega);
end if;
if Opcion = 'UPDATE' then
update inv_Bodegas set nom_Bodega = #NomBodega, dir_Bodega = #DirBodega where cod_Bodega = #CodBodega;
end if;
end;
Wanted to know how I can make it work so very similar in my application, I am using aspx and EF for my database.
Thanks.
You have declared the variable as NomBodega but when you are using it in your procedure you use #NomBodega.
The #NomBodega would only be required if you passed in an out parameter to select the value after the procedure has run.
Thanks for your help, but i was very busy.
After read a lot of SP MYSQL i find is not possible so. i gona send every value.
Is it possible to have a default parameter for a mysql stored procedure?
I have a table which contains some commercial Short text such as 'PVT, LTD' etc as in figure.
Secondly we have a new title received from another side every time such as 'Taha Zubair' and 'Taha PVT Ltd'.
Now i need to find just that if title contains a keyword, after scanning from database i need to return count only. If count is zero (0) means that title is simple as 'Taha Zubair' else return > 1 if title is some thing like that 'Taha PVT Ltd' or 'Taha Trust'
Image: http://social.msdn.microsoft.com/Forums/getfile/195838
Furthermore i need to do it some thing like that it would be adjust in stored Procedure, using whole query in programming application(Inline query) would affect the performance.
if you have any question ask it without any hesitation........
as function
Create Function F_GetNonIndividual(#SearchStr nVarchar(100)) Returns int
as -- use Select dbo.F_GetNonIndividual('Abc Solutions PVT LTD')
begin
Declare #Result int
Select #Result = Count(*)
from NonIndividualTitle
where #SearchStr Like ('%'+NonIndivTitle+'%')
Return #Result
end
as procedure
Create Procedure P_GetNonIndividual(#SearchStr nVarchar(100))
as -- use EXEC P_GetNonIndividual 'Abc Solutions PVT LTD'
begin
Select Count(*)
from NonIndividualTitle
where #SearchStr Like ('%'+NonIndivTitle+'%')
end
as procedure with out param
Create Procedure P_GetNonIndividualOut(#SearchStr nVarchar(100), #OutValue int out)
as
begin
Select #OutValue=Count(*)
from NonIndividualTitle
where #SearchStr Like ('%'+NonIndivTitle+'%')
end
with query example
Declare #OutValue int
exec P_GetNonIndividualOut 'Abc Solutions PVT LTD',#OutValue out
print #OutValue
This seems to be a simple question but nevertheless I haven't found an answer yet.
I have the following stored procedure
CREATE PROCEDURE [dbo].[AllocateId]
AS
BEGIN TRANSACTION
UPDATE TOP(1) IdReservation
SET IsAllocated = 1
OUTPUT DELETED.Id
WHERE IsAllocated = 0
COMMIT TRANSACTION
GO
It's been used in C# + EF code without a problem via ExecuteFunction of ObjectContext
ObjectResult<int> objectResult = ExecuteFunction<int>("AllocateId");
However when I try to call it directly from SQL script it doesn't seem to work
declare #Id int
EXEC #Id = [dbo].[AllocateId]
#Id is always 0. How do I get the value into #Id variable in sql script?
Procedure return value is different from result set(s) returned by that procedure. Your stored procedure returns a result set and does not return a return value (which ends up being null, which gets converted to 0 implicitly upon exiting the procedure).
To get the resultset your existing procedure retuns, you need insert ... exec:
declare #t table (id int);
insert into #t
exec [dbo].[AllocateId];
If you want to return a value as a return value as well, you should amend you stored procedure:
CREATE PROCEDURE [dbo].[AllocateId]
AS
BEGIN TRANSACTION
declare #id int;
UPDATE TOP(1) IdReservation
SET #id = Id, IsAllocated = 1
OUTPUT DELETED.Id
WHERE IsAllocated = 0
COMMIT TRANSACTION
return #id;
Then it will work in the way you describe in the question.