stored procedure too many arguments error - sql-server

i have written following stored procedure:
in which there are 2 tables arts and artist.artistId is a foreign key in arts table.
create procedure spInsertArts(
#artsId int out,
#name varchar(50),
#category varchar(50),
#artistId int
)
as
begin
declare #artistId int
set #artistId=##IDENTITY
if exists(select artistId from artist)
insert into arts(name,category,artistId) values(#name,#category,#artistId)
end
I am getting error as:
Procedure or function spInsertArts has too many arguments specified.
The code used to call this procedure is:
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#name", TextBox1.Text);
cmd.Parameters.AddWithValue("#category", DropDownList1.SelectedValue);
SqlParameter output = new SqlParameter();
output.ParameterName = "#artsId";
output.SqlDbType = System.Data.SqlDbType.Int;
output.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(output);
con.Open();
cmd.ExecuteNonQuery();
please help

You are not passing any value for parametere #artistId
Either pass a value or change procedure and set it default value null see below:
cmd.Parameters.AddWithValue("#artistId", "VALUE_HERE");
OR
create procedure spInsertArts(
#artsId int out,
#name varchar(50),
#category varchar(50),
#artistId int = null
)

output.ParameterName = "#artsId";
You are using "#artsId" where it should be "#artistId"

Based on your comment that you are aiming to use the last inserted record in the artist table you want to be using either:
DECLARE #artistId INT = IDENT_CURRENT('dbo.Artist');
Or simply
DECLARE #artistId INT = (SELECT MAX(ArtistID) FROM dbo.Artist);
CREATE PROCEDURE dbo.spInsertArts
#name VARCHAR(50),
#category VARCHAR(50),
#artsId INT OUT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM dbo.Artist)
BEGIN
DECLARE #artistId INT = (SELECT MAX(ArtistID) FROM dbo.Artist);
INSERT dbo.Arts (Name, Category, ArtistID)
VALUES (#Name, #Category, #ArtistID);
SET #ArtsID = SCOPE_IDENTITY();
END
END
I have made the following changes to your code:
Removed the redundant parameter #ArtistID and replaced it with a local variable.
Set #ArtsID after the insert.
Terminated all statements with a semi-colon
Used the schema prefix in all object references
Aaron Bertrand has done a great article called My stored procedure "best practices" checklist, which I tend to stick to, although some of it is personal preference, all of it is logical to me.
I really disagree with this logic though, it makes your procedure completely inflexible. What if you need to insert art for an artist that isn't the latest one? If inserting for the last artist is a real requirement then I'd suggest having two procedures:
CREATE PROCEDURE dbo.spInsertArts
#name VARCHAR(50),
#category VARCHAR(50),
#ArtistID INT,
#artsId INT OUT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Arts (Name, Category, ArtistID)
VALUES (#Name, #Category, #ArtistID);
END
GO
CREATE PROCEDURE dbo.spInsertArtsWithLatestArtist
#name VARCHAR(50),
#category VARCHAR(50),
#artsId INT OUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #artistId INT = (SELECT MAX(ArtistID) FROM dbo.Artist);
IF #ArtistID IS NOT NULL
BEGIN
EXECUTE dbo.spInsertArts #name, #category, #ArtistID, #artsID OUT;
END
END

Related

How Do I Solve Error "Expects Parameter" for stored procedure

I am getting this error
Msg 201, Level 16, State 4, Procedure sp_GetAllAirports, Line 0 [Batch Start Line 2]
Procedure or function 'sp_GetAllAirports' expects parameter '#AirportID', which was not supplied."
When I run
EXEC sp_GetAllAirports
The following is my stored procedure which shows #AirportID, what could be the issue?
IF OBJECT_ID('sp_GetAllAirports', 'P') IS NOT NULL
DROP PROCEDURE [dbo].[sp_GetAllAirports]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT,
#ICAOCode VARCHAR(4) NULL,
#AirportName VARCHAR(MAX),
#City VARCHAR(MAX),
#Lat DECIMAL(8,3),
#Long DECIMAL (11,3),
#Elevation INT,
#Country NVARCHAR(MAX)
AS
BEGIN TRANSACTION
BEGIN TRY
SET NOCOUNT ON
SET ANSI_WARNINGS OFF
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--SELECT * FROM tbl_Airports ORDER BY AirportID ASC
SELECT
AirportID, ICAOCode, AirportName, City,
Latitude, Longitude, Elevation, CountryFK
FROM
tbl_Airports
LEFT JOIN
tbl_Countries ON CountryID = tbl_Airports.CountryFK
WHERE
CountryID = tbl_Airports.CountryFK
ORDER BY
AirportID
END TRY
BEGIN CATCH
DECLARE #ErMessage NVARCHAR(MAX),
#ErSeverity INT,
#ErState INT
SELECT
#ErMessage = ERROR_MESSAGE(),
#ErSeverity = ERROR_SEVERITY(),
#ErState = ERROR_STATE()
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END
RAISERROR(#ErMessage, #ErSeverity, #ErState)
END CATCH
IF ##TRANCOUNT > 0
BEGIN
COMMIT TRANSACTION
END
GO
Your stored procedure is defined to expect arguments (AirportID, ICAOCode, AirportName, City, Lat, Long, Elevation and Country):
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT,
#ICAOCode VARCHAR(4) NULL,
#AirportName VARCHAR(MAX),
#City VARCHAR(MAX),
#Lat DECIMAL(8,3),
#Long DECIMAL (11,3),
#Elevation INT ,
#Country NVARCHAR(MAX)
AS
...
However, it doesn't use any of them. So you probably just need to remove them:
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
AS
...
Alternatively, make sure the arguments are used in the SP (so it makes sense to expect arguments) and pass values accordingly (sp_GetAllAirports 1234) e.g.:
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT
AS
....
SELECT AirportID, ICAOCode, AirportName, City, Latitude, Longitude, Elevation, CountryFK
FROM tbl_Airports
LEFT JOIN tbl_Countries ON CountryID = tbl_Airports.CountryFK
WHERE CountryID = tbl_Airports.CountryFK
AND AirportID = #AirportID -- Using first argument here
ORDER BY AirportID
....
Or, finally, give the arguments default values, e.g:
CREATE PROCEDURE [dbo].[sp_GetAllAirports]
#AirportID INT = NULL,
#ICAOCode VARCHAR(4) = 'FOO',
...
AS
...
That way you won't have to explicitly pass any argument values. However, you'll still need to use the arguments to having the arguments make sense in the first place.

How to get and use the value returned by a stored procedure to a INSERT INTO... SELECT... statement

I am just new in SQL language and still studying it. I'm having hard time looking for answer on how can I use the stored procedure and insert value into a table.
I have this stored procedure:
CREATE PROCEDURE TestID
AS
SET NOCOUNT ON;
BEGIN
DECLARE #NewID VARCHAR(30),
#GenID INT,
#BrgyCode VARCHAR(5) = '23548'
SET #GenID = (SELECT TOP (1) NextID
FROM dbo.RandomIDs
WHERE IsUsed = 0
ORDER BY RowNumber)
SET #NewID = #BrgyCode + '-' + CAST(#GenID AS VARCHAR (30))
UPDATE dbo.RandomIDs
SET dbo.RandomIDs.IsUsed = 1
WHERE dbo.RandomIDs.NextID = #GenID
SELECT #NewID
END;
and what I'm trying to do is this:
INSERT INTO dbo.Residents([ResidentID], NewResidentID, [ResLogdate],
...
SELECT
[ResidentID],
EXEC TestID ,
[ResLogdate],
....
FROM
source.dbo.Resident;
There is a table dbo.RandomIDs containing random 6 digit non repeating numbers where I'm pulling out the value via the stored procedure and updating the IsUsed column of the table to 1. I'm transferring data from one database to another database and doing some processing on the data while transferring. Part of the processing is generating a new ID with the required format.
But I can't get it to work Sad I've been searching the net for hours now but I'm not getting the information that I need and that the reason for my writing. I hope someone could help me with this.
Thanks,
Darren
your question is little bit confusing, because you have not explained what you want to do. As i got your question, you want to fetch random id from randomids table and after performed some processing on nextid you want to insert it into resident table [newresidentid] and end of the procedure you fetch data from resident table. if i get anything wrong feel free to ask me.
your procedure solution is following.
CREATE PROCEDURE [TestId]
AS
SET NOCOUNT ON;
BEGIN
DECLARE #NEWID NVARCHAR(30)
DECLARE #GENID BIGINT
DECLARE #BRGYCODE VARCHAR(5) = '23548'
DECLARE #COUNT INTEGER
DECLARE #ERR NVARCHAR(20) = 'NO IDS IN RANDOM ID'
SET #COUNT = (SELECT COUNT(NEXTID) FROM RandomIds WHERE [IsUsed] = 0)
SET #GENID = (SELECT TOP(1) [NEXTID] FROM RandomIds WHERE [IsUsed] = 0 ORDER BY [ID] ASC)
--SELECT #GENID AS ID
IF #COUNT = 0
BEGIN
SELECT #ERR AS ERROR
END
ELSE
BEGIN
SET #NEWID = #BRGYCODE + '-' + CAST(#GENID AS varchar(30))
UPDATE RandomIds SET [IsUsed] = 1 WHERE [NextId] = #GENID
INSERT INTO Residents ([NewResidentId] , [ResLogDate] ) VALUES (#NEWID , GETDATE())
SELECT * FROM Residents
END
END
this procedure will fetch data from your randomids table and perform some processing on nextid than after it directs insert it into resident table and if you want to insert some data through user you can use parameter after declaring procedure name
E.G
CREATE PROCEDURE [TESTID]
#PARAM1 DATATYPE,
#PARAM2 DATATYPE
AS
BEGIN
END
I'm not convinced that your requirement is a good one but here is a way to do it.
Bear in mind that concurrent sessions will not be able to read your update until it is committed so you have to kind of "lock" the update so you will get a block until you're going to commit or rollback. This is rubbish for concurrency, but that's a side effect of this requirement.
declare #cap table ( capturedValue int);
declare #GENID int;
update top (1) RandomIds set IsUsed=1
output inserted.NextID into #cap
where IsUsed=0;
set #GENID =(select max( capturedValue) from #cap )
A better way would be to use an IDENTITY or SEQUENCE to solve your problem. This would leave gaps but help concurrency.

Run A Loop in SQL Server

I want to run a stored procedure on each ID return by a SELECT query. Is there a simple way to do something like:
FOREACH (SELECT ID FROM myTABLE WHERE myName='bob') AS id
BEGIN
EXEC #return_value = [dbo].[spMYPROC]
#PARAM1 = id
#PARAM2 = 0
END
Since I just happened to answer a very similar question yesterday, I have this code handy. As others have stated, it may not be the best approach, but still it's nice to learn how to use a while loop anyway.
Assuming a table named "Customer"
declare #Id int
select #Id = MIN(Id)
from Customer c
while(select COUNT(1)
from Customer c
where c.Id >= #Id) > 0
begin
--run your sproc right here
select #Id = MIN(Id)
from Customer c
where c.Id > #Id
end
DECLARE #ID INT, #return_value INT
DECLARE c CURSOR FOR
SELECT
ID
FROM myTABLE
WHERE myName = 'bob'
OPEN c; FETCH NEXT FROM c INTO #ID
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC #return_value = [dbo].[spMYPROC]
#PARAM1 = #ID,
#PARAM2 = 0
FETCH NEXT FROM c INTO #ID
END
CLOSE c; DEALLOCATE c;
You have two option here
Option 1 Using Split Function
Pass a comma deliminated list of IDs and use a Split function Inside your Procedure to make split these values and do whatever you want to do with it.
To
Make it work you will need two thing
1) Create a Function which
accepts a Comma Deliminated string and split them.
2) Modify you
Store Procedure and add this function in there in a way that passed
parameter is passed to the function inside that store procedure and
that function split the values before passing it onto your store
Procedure .
Create this function 1st
Function Definition
CREATE FUNCTION [dbo].[FnSplit]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table (Id int identity(1,1), Value nvarchar(100))
AS
BEGIN
WHILE(Charindex(#SplitOn,#List)>0)
BEGIN
INSERT INTO #RtnValue (value)
SELECT VALUE = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
SET #List = SUBSTRING(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
END
INSERT INTO #RtnValue (Value)
SELECT VALUE = ltrim(rtrim(#List))
RETURN
END
Modify you strored Procedure something like this
Stored Procedure
ALTER Procedure [dbo].[spMYPROC] (#Param1 VARCHAR(1000)= NULL)
AS
BEGIN
SELECT * FROM TableName
where ColumnNAME IN (SELECT Value FROM dbo.FnSplit(#Param1,','))
END
GO
Option 2 Table Type Parameter
Create a Table Type and alter your proc to accept a Table Type Parameter and do whatever you want to do with them values inside your proc.
TABLE TYPE
CREATE TYPE dbo.TYPENAME AS TABLE
(
Value int
)
GO
Stored Procedure to Accept That Type Param
ALTER PROCEDURE [dbo].[spMYPROC]
#TableParam TYPENAME READONLY
AS
BEGIN
SET NOCOUNT ON;
--Temp table to store passed Id values
declare #tmp_values table (value INT );
--Insert passed values to a table variable inside the proc
INSERT INTO #tmp_values (value)
SELECT Value FROM #TableParam
/* Do your stuff here whatever you want to do with Ids */
END
EXECUTE PROC
Declare a variable of that type and populate it with your values.
DECLARE #Table TYPENAME --<-- Variable of this TYPE
INSERT INTO #Table --<-- Populating the variable
SELECT ID FROM myTABLE WHERE myName='bob'
EXECUTE [dbo].[spMYPROC] #Table --<-- Stored Procedure Executed

SQL Server: how to create a stored procedure

I'm learning sql from a book and I'm trying to write a stored procedure but I don't believe that I'm doing it correctly. Is the following way not valid in Microsoft SQL? If not, when is it valid, if ever?
create procedure dept_count(in dept_name varchar(20), out d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
I get the following error
Msg 156, Level 15, State 1, Procedure wine_change, Line 1
Incorrect syntax near the keyword 'in'.
T-SQL
/*
Stored Procedure GetstudentnameInOutputVariable is modified to collect the
email address of the student with the help of the Alert Keyword
*/
CREATE PROCEDURE GetstudentnameInOutputVariable
(
#studentid INT, --Input parameter , Studentid of the student
#studentname VARCHAR (200) OUT, -- Output parameter to collect the student name
#StudentEmail VARCHAR (200)OUT -- Output Parameter to collect the student email
)
AS
BEGIN
SELECT #studentname= Firstname+' '+Lastname,
#StudentEmail=email FROM tbl_Students WHERE studentid=#studentid
END
In T-SQL stored procedures for input parameters explicit 'in' keyword is not required and for output parameters an explicit 'Output' keyword is required. The query in question can be written as:
CREATE PROCEDURE dept_count
(
-- Add input and output parameters for the stored procedure here
#dept_name varchar(20), --Input parameter
#d_count int OUTPUT -- Output parameter declared with the help of OUTPUT/OUT keyword
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Statements for procedure here
SELECT #d_count = count(*)
from instructor
where instructor.dept_name=#dept_name
END
GO
and to execute above procedure we can write as:
Declare #dept_name varchar(20), -- Declaring the variable to collect the dept_name
#d_count int -- Declaring the variable to collect the d_count
SET #dept_name = 'Test'
Execute dept_count #dept_name,#d_count output
SELECT #d_count -- "Select" Statement is used to show the output
I think it can help you:
CREATE PROCEDURE DEPT_COUNT
(
#DEPT_NAME VARCHAR(20), -- Input parameter
#D_COUNT INT OUTPUT -- Output parameter
-- Remember parameters begin with "#"
)
AS -- You miss this word in your example
BEGIN
SELECT COUNT(*)
INTO #D_COUNT -- Into a Temp Table (prefix "#")
FROM INSTRUCTOR
WHERE INSTRUCTOR.DEPT_NAME = DEPT_COUNT.DEPT_NAME
END
Then, you can call the SP like this way, for example:
DECLARE #COUNTER INT
EXEC DEPT_COUNT 'DeptName', #COUNTER OUTPUT
SELECT #COUNTER
Try this:
create procedure dept_count(#dept_name varchar(20),#d_count int)
begin
set #d_count=(select count(*)
from instructor
where instructor.dept_name=dept_count.dept_name)
Select #d_count as count
end
Or
create procedure dept_count(#dept_name varchar(20))
begin
select count(*)
from instructor
where instructor.dept_name=dept_count.dept_name
end
CREATE PROCEDURE [dbo].[USP_StudentInformation]
#S_Name VARCHAR(50)
,#S_Address VARCHAR(500)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Date VARCHAR(50)
SET #Date = GETDATE()
IF EXISTS (
SELECT *
FROM TB_StdFunction
WHERE S_Name = #S_Name
AND S_Address = #S_Address
)
BEGIN
UPDATE TB_StdFunction
SET S_Name = #S_Name
,S_Address = #S_Address
,ModifiedDate = #Date
WHERE S_Name = #S_Name
AND S_Address = #S_Address
SELECT *
FROM TB_StdFunction
END
ELSE
BEGIN
INSERT INTO TB_StdFunction (
S_Name
,S_Address
,CreatedDate
)
VALUES (
#S_Name
,#S_Address
,#date
)
SELECT *
FROM TB_StdFunction
END
END
Table Name : TB_StdFunction
S_No INT PRIMARY KEY AUTO_INCREMENT
S_Name nvarchar(50)
S_Address nvarchar(500)
CreatedDate nvarchar(50)
ModifiedDate nvarchar(50)
Create this way.
Create procedure dept_count(dept_name varchar(20),d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
try this:
create procedure dept_count( #dept_name varchar(20), #d_count INTEGER out)
AS
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
To Create SQL server Store procedure in SQL server management studio
Expand your database
Expand programmatically
Right-click on Stored-procedure and Select "new Stored Procedure"
Now, Write your Store procedure, for example, it can be something like below
USE DatabaseName;
GO
CREATE PROCEDURE ProcedureName
#LastName nvarchar(50),
#FirstName nvarchar(50)
AS
SET NOCOUNT ON;
//Your SQL query here, like
Select FirstName, LastName, Department
FROM HumanResources.vEmployeeDepartmentHistory
WHERE FirstName = #FirstName AND LastName = #LastName
GO
Where, DatabaseName = name of your database
ProcedureName = name of SP
InputValue = your input parameter value (#LastName and #FirstName) and type = parameter type example nvarchar(50) etc.
Source: Stored procedure in sql server (With Example)
To Execute the above stored procedure you can use sample query as below
EXECUTE ProcedureName #FirstName = N'Pilar', #LastName = N'Ackerman';

Calling a stored proc that returns a recordset from within a stored proc

Working in SQL Server 2005, I have a stored procedure that inserts a record and returns the new ID via SELECT ##IDENTITY; as the last command.
I then want to call this from another stored proc, and get the value of the new ID.
But I can't work out how to get the value returned from the first procedure.
Example:
CREATE PROCEDURE spMyInsert(#Field1 VARCHAR(10)) AS
BEGIN
INSERT INTO tMyTable (Column1) VALUES (#Field1); // ID column implicitly set
SELECT ##IDENTITY ID;
END
CREATE PROCEDURE spMyMain AS
BEGIN
DECLARE #NewID INT;
EXEC spMyInsert 'TEST';
// How do I set #NewID to the value returned from spMyInsert?
END
There is another question that nearly answers my question, but not quite. This explains how to insert the results into another table, but all I want to do is store it in a local variable.
Looking at other similar questions, the general answer is to change to either set an OUTPUT variable or create a function to do it, but I can't do this in my case as other .NET data access stuff uses the same stored proc, and I don't want to have to duplicate all the work of the stored procs as functions as well.
I couple of things that I've tried but all fail are:
SET #NewID = (EXEC spMyInsert 'TEST');
SET #NewID = (SELECT ID FROM (EXEC spMyInsert 'TEST'));
Anybody know how to do this?
Thanks,
Ben
By the way you should probably check that ##identity is what you need as opposed to scope_identity.
If it is what you need then it will still be accessible in the calling stored procedure too.
CREATE PROCEDURE spMyMain
AS
BEGIN
DECLARE #NewID INT;
EXEC spMyInsert 'TEST';
SET #NewID = ##IDENTITY
SELECT #NewID AS '#NewID'
END
The more general solution that would need to be applied if you use scope_identity and don't want to use either output parameters or the procedure return code is
CREATE PROCEDURE spMyMain AS
BEGIN
DECLARE #NewID INT;
DECLARE #IdHolder TABLE
(
id INT
)
INSERT INTO #IdHolder
EXEC spMyInsert 'TEST';
IF ##ROWCOUNT<>1
RAISERROR('Blah',16,1)
SELECT #NewID = id FROM #IdHolder
END
First, don't use ##IDENTITY, use SCOPE_IDENTITY() instead (search this site or Google for the reason why). Then just return the value in an output parameter:
CREATE PROCEDURE spMyInsert(#Field1 VARCHAR(10), #NewID int output) AS
BEGIN
INSERT INTO tMyTable (Column1) VALUES (#Field1);
SET #NewID = scope_identity();
END
go
CREATE PROCEDURE spMyMain AS
BEGIN
DECLARE #NewID INT;
EXEC spMyInsert #Field1 = 'TEST', #NewID = #NewID OUTPUT;
END
go
The issue here is that the spMyInsert returns a Select. When you execute spMyMain it will return the Select from spMyInsert and then the select from spMyMain
I would suggest that you amend spMyInsert to utilise OUTPUT parameters
CREATE PROCEDURE spMyInsert(#Field1 VARCHAR(10), #NewId int output) AS
BEGIN
INSERT INTO tMyTable (Column1) VALUES (#Field1); // ID column implicitly set
SELECT #NewId = ##SCOPE_IDENTITY;
END
and then
CREATE PROCEDURE spMyMain AS
BEGIN
DECLARE #NewID INT;
Set #NewId = 0
EXEC spMyInsert 'TEST', #NewId output;
select #NewId
// How do I set #NewID to the value returned from spMyInsert?
END
Note that I have also changed ##Identity to ##scope_identity It is better to use ##Scope_Identity as that will return the new ID that applies to the current connection.
Try this:
Execute #NewID = spMyInsert 'TEST'
Edit: After reading his question more thoroughly and realizing he was dealing with a select rather than a return: Could you wrap that procedure in a function call and then call the function?
select #NewId = from fnMyInsert('TEST')
An output parameter is the way to go, but if you really can't change the inner SP then, as you say, you can have the inner SP return its results to a table and then get the value out of there.
eg.
declare #NewID int,
#Customer table(CustomerId int);
insert into #Customer
exec spMyInsert 'TEST';
select #NewID = CustomerId from #Customer;

Resources