Too many arguments specified error in stored proc
I'm getting a 'too many arguments specified' error when I call my stored proc. I've assigned the stored proc to a SqlDataAdapter and a DataSet which is called when the SqlDataAdapter.InsertCommand is called. I've checked the numbers of variables and I can't see where there is a mismatch in the number of arguments being called. I assume that this error has something to do with how I am retrieving the SQL autonumbered identity column (CitationID) with SCOPE_IDENTITY(). If someone could look over my code and let me know what I'm doing wrong, I would greatly appreciate it.
Stored Proc:
ALTER PROCEDURE
tbl_Citations_AddNewRow@CitationType
nvarchar(6),@ARTFlag
nvarchar(7),@Title
nvarchar(1000),@PublicationDate
datetime,@EPublicationDate
datetime,@Abstract
text,@Notes
nvarchar(4000),@Pages
nvarchar(500),@Volume
nvarchar(1000),@Issue
nvarchar(1000),@Publisher
nvarchar(1000),@PubLoc
nvarchar(1000),@LinkToPDF
nvarchar(1000),@RelatedLinks
nvarchar(1000),@PMID
nvarchar(1000),@Identity
decimalOUTAS
INSERT INTO
tbl_Citations (CitationType, ARTFlag, Title, PublicationDate, EPublicationDate, Abstract, Notes, Pages, Volume, Issue, Publisher, PubLoc, LinkToPDF, RelatedLinks, PMID)VALUES(@CitationType, @ARTFlag, @Title, @PublicationDate, @EPublicationDate, @Abstract, @Notes, @Pages, @Volume, @Issue, @Publisher, @Publoc, @LinkToPDF, @RelatedLinks, @PMID)SET
@Identity =SCOPE_IDENTITY()Program Code:
SqlConnection Connection_tbl_Citations =newSqlConnection(SQLConnectionString_Dans);string queryString_tbl_Citations ="SELECT CitationID, CitationType, ARTFlag, Title, PublicationDate, EPublicationDate, " +"Abstract, Notes, Pages, Volume, Issue, Publisher, PubLoc, LinkToPDF, RelatedLinks, PMID " +"FROM tbl_Citations;";tbl_Citations_Adapter =
newSqlDataAdapter(queryString_tbl_Citations, Connection_tbl_Citations);tbl_Citations =
newDataSet();tbl_Citations_Adapter.Fill(tbl_Citations,
"tbl_Citations");tbl_Citations_Adapter.InsertCommand =
newSqlCommand("tbl_Citations_AddNewRow", Connection_tbl_Citations);tbl_Citations_Adapter.InsertCommand.CommandType =
CommandType.StoredProcedure;tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@CitationType",SqlDbType.NVarChar, 6,"CitationType");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@ARTFlag",SqlDbType.NVarChar, 7,"ARTFlag");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Title",SqlDbType.NVarChar, 1000,"Title");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@PublicationDate",SqlDbType.DateTime, 8,"PublicationDate");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@EPublicationDate",SqlDbType.DateTime, 8,"EPublicationDate");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Abstract",SqlDbType.Text, 16,"Abstract");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Notes",SqlDbType.NVarChar, 4000,"Notes");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Pages",SqlDbType.NVarChar, 500,"Pages");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Volume",SqlDbType.NVarChar, 1000,"Volume");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Issue",SqlDbType.NVarChar, 1000,"Issue");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@Publisher",SqlDbType.NVarChar, 1000,"Publisher");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@PubLoc",SqlDbType.NVarChar, 1000,"PubLoc");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@LinkToPDF",SqlDbType.NVarChar, 1000,"LinkToPDF");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@RelatedLinks",SqlDbType.NVarChar, 1000,"RelatedLinks");tbl_Citations_Adapter.InsertCommand.Parameters.Add(
"@PMID",SqlDbType.NVarChar, 9,"PMID");SqlParameter tbl_Citations_Identity = tbl_Citations_Adapter.InsertCommand.Parameters.Add("@Identity",SqlDbType.Decimal, 9,"CitationID");tbl_Citations_Identity.Direction =
ParameterDirection.Output;DataRow newRow;decimal tbl_Citation_returnValue;decimal tbl_Citations_Project_returnValue;decimal tbl_Citations_Location_returnValue;for (int rep = 0; rep < CitData.Count; rep++){
//populate tbl_CitationsnewRow = tbl_Citations.Tables[
"tbl_Citations"].NewRow();newRow[
"CitationType"] = CitData[rep].CitationType;newRow[
"ARTFlag"] = CitData[rep].ARTFlag;newRow[
"Title"] = CitData[rep].Title;newRow[
"PublicationDate"] = CitData[rep].PublicationDate.StrSqlDateTime();newRow[
"EPublicationDate"] = CitData[rep].EPublicationDate.StrSqlDateTime();newRow[
"Abstract"] = CitData[rep].Abstract;newRow[
"Notes"] = CitData[rep].Notes;newRow[
"Pages"] = CitData[rep].Pages;newRow[
"Volume"] = CitData[rep].Volume;newRow[
"Issue"] = CitData[rep].Issue;newRow[
"Publisher"] = CitData[rep].Publisher;newRow[
"PubLoc"] = CitData[rep].PubLoc;newRow[
"LinkToPDF"] = CitData[rep].LinkToPDF;newRow[
"RelatedLinks"] = CitData[rep].RelatedLinks;newRow[
"PMID"] = CitData[rep].PMID;tbl_Citations.Tables[
"tbl_Citations"].Rows.Add(newRow);tbl_Citations_Adapter.Update(tbl_Citations,
"tbl_Citations");tbl_Citation_returnValue = (
decimal)tbl_Citations.Tables["tbl_Citations"].Rows[rep].ItemArray[0];}
Error message:
System.Data.SqlClient.SqlException was unhandled
Message="Procedure or function tbl_Citations_AddNewRow has too many arguments specified."
Source=".Net SqlClient Data Provider"
ErrorCode=-2146232060
Class=16
LineNumber=0
Number=8144
Procedure="tbl_Citations_AddNewRow"
Server="****"
State=2
StackTrace:
at System.Data.Common.DbDataAdapter.UpdatedRowStatusErrors(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount)
at System.Data.Common.DbDataAdapter.UpdatedRowStatus(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount)
... blah blah...
no idea if this will help but be sure to CLEAR the parameter collection at the end of the executing statement otherwise it will keep adding parameters and causing this type of error.
so at the end of the for loop or after you execute the command, clear the SQL Parameters collection
this is what it looks like to me.
use
.Parameters.Clear();
His parameters are not being added in the for loop...He is adding rows to the citations table in the for loop from citdata. I would take a look at the parameter @Identity...change
tbl_Citations_Identity.Direction = ParameterDirection.Output;
to
tbl_Citations_Identity.Direction = ParameterDirection.ReturnVal;
also...
tbl_Citation_returnValue = tbl_Citations_Identity.Value;
OK, that last bit worked ... once.
This is where things get really odd. I went ahead and changed the ParameterDirection to ReturnVal and the proc ran flawlessly. (or at least for the single iteration of the for loop I let it go through on that run).
The next time I ran the proc, I got:
"Procedure 'tbl_Citations_AddNewRow' expects parameter '@Identity', which was not supplied."
I double-checked everything and nothing in the stored proc had changed. I tried changing the ParameterDirection to InputOutput to see what would happen. It ran once (unfortunately I only let the for loop go one iteration again so I don't know what happens on multiple calls in a singel program instance)
Guess what - the next time I ran the program, I started getting the 'too many arguments error' again.
I've tried running several times but both ReturnVal and InputOutput now fail to work. ReturnVal now always gives the '@Identity' error and InputOutput always give the 'too many params' error. I've checked my tables and stored procs to see if anything has changed but everything is unhanged. I've tested the stored proc in SQL Query Analyzer and it works fine and returns @Identity just fine.
Any suggestions?
I'll take a look further but I've never had the issue with scope_identity as I I sometimes use it myself. :-)
Just out of interest, what happens when you change the field type from decimal to int?
Hoooookay... I've figured out the problem. Wait, no, that's wording it too strongly. I've gotten rid of the error. I still have no idea of how I did it, though.
So, I'm thrashing around with the stored proc since it looks like the error is originating from there. One interesting thing that I notice is that the stored proc runs just fine from SQL Query Analyzer and returns the autogenerated row number like it's supposed to. However, when run from within Visual Studio, I get the same @Identity error and the stored proc neither adds a table row nor returns a row number.
I borrow a copy of Professional SQL Server 2000 Programming by Robert Vieira. Good 'ol Roberto has the following to say on page 367:
"You must use the OUTPUT keyword when you call the sproc, much as you did when you declared the sproc. This gives SQL Server advance warning about the special handling that parameter will require. Be aware, however, that forgetting to include the OUTPUT keyword won't create a runtime error, but the value for the output parameter won't be moved into your variable (you'll just wind up with what was already there - most likely a NULL value). ..."
Since this sounded a lot like the @Identity error I was getting, I took a closer look at the @Identity definition in the stored proc on the assumption that something is failing to let SQL Server know in advance that the stored proc has an OUTPUT return value. The variable initialization dialog box that pops up when you run the stored proc has a dropdown box for initializing the value of @Identity which seems wierd because it's an OUTPUT variable. The two options are <DEFAULT> (the default setting in the dropdown) and <NULL>.
More as a result of being out of ideas than any rational thought process, I change <DEFAULT> to <NULL> in the dialog box and run the stored proc.
It runs flawlessly.
So now I spend some time thrashing around trying to figure out how to get my C# code to tell the stored proc that @Identity needs to be <NULL> be default. What finally ends up working - I kid you not - is this:
@Identity
decimal OUTPUT gets changed to this:
@Identity
decimal = NULL OUTPUT and everything lives happily ever after.
Except me since I still don't know why I have to explicitly define an OUTPUT variable as being NULL. I'd be a lot happier if my solution didn't involve the programming equivalent to swinging a dead cat around my head and making a ward against the evil eye.
But, in the end, it works so I can't complain too much. Thanks ahmedilyas and DMan1, your help is greatly appreciated even if it didn't directly lead to the (rather bizzare) solution.
Dan
Thanks Dan
all I can say is...
interesting. o_0
I've never had to do that in the sproc, but only as you did before:
DECLARE @someVar datatype output
Nice to know you got it solved though!
Wait, it gets better!
I noticed this morning that the stored proc in my code above runs fine but the return value in my code *always* returns 0. However, my other 3 stored procs work just fine.(I'm working with nested data - the code I posted above is only a small part of it - there are 3 other tables chained in one-to-many relationships to the first table that I am populating at the same time in a similar way. All of the other tables have the same sort of stored proc, etc and the return value comes back exactly how one would expect.)
To try and troubleshoot, I add RETURN @Identity to the end of the problematic stored proc, intending to see if I can grab the return value and have better luck with that. Of course, I forgot to change my C# code to refer to the RETURN value rather than the returned @Identity.
I notice this just as I trace to the line where I get the return value and expect to get a 0 again. But no, now @Identity returns its value just fine. Because there's a RETURN statement after it.
Of course, why didn't I think of that...
Then I finally realize why this one table is acting differently than the other 3 - while messing with the ParameterDirection settings for the @Identity variables, the code that handles the problematic table is set to ReturnValue while the other 3 are set to InputOutput. As soon as I change my code to InputOutput for all the stored proc @Identity variables, it works fine.
So, to sum up:
- Assign a default value of NULL to your return variable or else you get SQL exceptions complaining that your return variable isn't returning a value or that you have the wrong number of variables. (this still is true even with the latest developments - I tested)
- Use ParameterDirection.InputOutput in your code to get the value of that return variable
- If you use ParameterDirection.ReturnValue, you will always get 0 for that value unless you include a superfluous RETURN statement that returns the return variable a second time in the stored proc
Makes perfect sense to me. No if you'll excuse me, I have to go stock up on shrunken heads and voodoo dolls.
:P