sp_executesql sets a column to null - sql

I'm attempting to execute some SQL inside of sp_executesql.
Here is the generated SQL:
exec sp_executesql
N'declare #RC int
EXECUTE #RC = [dbo].[sp_StoredProcedureName]
#parameterName
select #RC',
N'#parameterName nvarchar(4000)',
#parameterName=N'TEST'
Here is the stored procedure that is called from the generated SQL:
ALTER PROCEDURE [dbo].[sp_StoredProcedureName] (
#parameterName varchar(4000)
)
with execute as owner
as
DECLARE #returnValue int
BEGIN TRANSACTION
INSERT INTO [dbo].[TableName]
(parameterName)
VALUES
(#parameterName)
set #returnValue = IDENT_CURRENT('TableName')
COMMIT
SELECT #returnValue
GO
For some reason, parameterName is never set.
When attempting to select from TableName after the SP has been executed, ParameterName is NULL.
I am using MS SQL. The SQL was generated by ADO.NET.

Your stored procedure is not returning anything, hence the return value is NULL.
In general, you should only be using the return value from a stored procedure as a status, not to return actual data.
Real return values should be returned via output parameters.
Further, I strongly recommend an OUTPUT clause for this purpose:
ALTER PROCEDURE [dbo].[sp_StoredProcedureName] (
#parameterName varchar(4000),
#returnValue int OUTPUT
)
with execute as owner
as
BEGIN
DECLARE #ids TABLE (id int);
INSERT INTO [dbo].[TableName] (parameterName)
OUTPUT id INTO #ids
VALUES (#parameterName);
SELECT TOP (1) #returnValue = id -- only 1 is expected anyway
FROM #ids;
END;
You would then call this as:
declare #RC int;
declare #parameterName nvarchar(4000);
set #parameterName = N'TEST';
exec [dbo].[sp_StoredProcedureName] #parameterName, #rc int OUTPUT;
Dynamic SQL is not necessary.

Related

Get result parameter of stored procedure in exec clause

I have a stored procedure that returns multiple parameters:
CREATE PROCEDURE [dbo].[TestSP]
#Test1 INT
, #Test2 UNIQUEIDENTIFIER
--some inserts and alters here
SELECT TOP 1
#Parameter1 AS Design
, #Parameter2
, #Parameter3
FROM Table
I want to use EXEC into another stored procedure and get ONLY #Parameter1 (Design)
So I want to get #Parameter1 after EXEC stored procedure, so I think about OUTPUT, but it doesn't work, is there a way to achieve this?
CREATE PROCEDURE [dbo].[SecondStoredProcedure]
#Sender1 INT
, #Sender2 UNIQUEIDENTIFIER
DECLARE #ReturnedParameter1 INT
EXEC [dbo].[TestSP] #Test1 = #Sender1, #Test2 = #Sender2 OUTPUT [Design]
INTO #ReturnedParameter1
SELECT #ReturnedParameter1
That procedure creates a resultset, and has no output parameters. You can capture a resultset with insert into ... exec, like this:
use tempdb
go
CREATE PROCEDURE [dbo].[addDesign]
#Test1 INT
,#Test2 UNIQUEIDENTIFIER
as
begin
--some inserts and alters here
SELECT
1 AS Design
, 2 as Foo
, 3 as Bar
end
go
declare #rv table(Design int, Foo int, Bar int)
declare #test2 uniqueidentifier = newid()
insert into #rv
exec addDesign 1, #test2
declare #design int = (select Design from #rv)
select #design
I suggest using an output parameter as explained in the official docs.
Here is how your code might look in this case:
use tempdb
go
create procedure [dbo].[addDesign]
(
#Test1 int
, #Test2 uniqueidentifier
, #Design int out
)
as
begin
set nocount on;
--some inserts and alters here
-- Set the return parameter
set #Design = #Parameter1;
-- Select the return results
SELECT TOP 1
#Parameter1
, #Parameter2
, #Parameter3
FROM dbo.MyTable;
-- Return status code, proc ran OK
return 0;
end
go
create procedure [dbo].[SecondStoredProcedure]
(
#Sender1 int
, #Sender2 uniqueidentifier
)
as
begin
set nocount on;
declare #ReturnedParameter1 int;
exec dbo.TestSP #Test1 = #Sender1, #Test2 = #Sender2, #Design = #ReturnedParameter1;
select #ReturnedParameter1;
-- Return status code, proc ran OK
return 0;
end
go
Note: This demonstrates the 3 ways information can be returned from a stored procedure, the result code (only 1), output parameters (0-N) and result sets (0-N).

Stored procedure with a parameter in FROM clause

Is it possible to create a stored procedure that uses a parameter in the FROM clause?
For example:
CREATE PROCEDURE [dbo].[GetMaxId]
#id varchar(50)
#table varchar(50)
AS
BEGIN
SELECT MAX(#id)
FROM #table
END
You cannot pass identifiers as parameters into a query (neither table names nor column names). The solution is to use dynamic SQL. Your syntax suggests SQL Server, so this would look like:
CREATE PROCEDURE [dbo].[GetMaxId] (
#id varchar(50)
#table varchar(50)
)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT MAX(#id) FROM #table';
SET #sql = REPLACE(REPLACE(#sql, '#id', QUOTENAME(#id)), '#table', QUOTENAME(#table));
EXEC sp_executesql #sql;
END; -- GetMaxId

How to update SQL field using function and stored procedure?

What I want to do is to update column (NewID) in my table (SampleTable) with the following code, but it's not working.. can somebody help me please? Whats wrong with it?
I have the table 'SampleTable' wich has the fields 'NewID' and 'OldID'.
UPDATE SampleTable SET NewID = dbo.fn_DoStuff(OldID) <-- Not working
My function:
ALTER FUNCTION [dbo].[fn_DoStuff]
(
#int oldid
)
RETURNS int
AS
BEGIN
DECLARE #returnValue int
EXEC #returnValue = dbo.spc_DoStuff #oldid
RETURN #returnValue
END
My stored procedure:
SampleTable1 has the columns ID, SomeColName.
ALTER PROCEDURE [dbo].[spc_GeraAtriðisorðalistaÚrAtriðisorði]
(
#oldid int
)
AS
BEGIN
DECLARE #returnValue int
INSERT INTO SampleTable1 (SomeColName) VALUES (null)
SET #returnValue = ##IDENTITY
INSERT INTO SampleTable2 (SomeColName1, SomeColName2) VALUES (#returnValue, #oldid)
SELECT #returnValue AS RetVal
END
You have 2 problems, the first is you cannot call a stored procedure inside a function, nor can you perform your insert within a function.
The second problem is that even if you could call a stored procedure inside a function, you are not returning the value from the procedure correctly. You would need something like:
CREATE TABLE dbo.T (ID INT IDENTITY, Filler CHAR(10));
GO
CREATE PROCEDURE dbo.Test
AS
DECLARE #i INT;
INSERT dbo.T (Filler) VALUES (NULL);
RETURN SCOPE_IDENTITY();
GO
Note the use of the RETURN statement, if you don't use this the default return value is 0
Then you can use:
DECLARE #i INT;
EXECUTE #i = dbo.Test;
SELECT ReturnVal = #i;
*Note, I have replaced ##IDENTITY with SCOPE_IDENTITY(), ##IDENTITY is rarely the correct function to use*
Example on SQL Fiddle
With your solution GarethD I could still not call the function like I wanted to
UPDATE SampleTable SET NewID = dbo.fn_DoStuff(OldID).
Your code helped me though to start thinking another way. Now I'm using a cursor and a while loop and it works perfectly. See my solution below:
DECLARE #OldID AS INT
DECLARE Upd_CURSOR FOR
SELECT OldID
FROM dbo.SampleTable
WHERE OldID is not null
FOR UPDATE OF NewID
OPEN Upd_CURSOR;
FETCH NEXT FROM Upd_CURSOR INTO #OldID
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #returnValue int;
INSERT INTO SampleTable1 (SomeColName) VALUES (null);
SET #returnValue = SCOPE_IDENTITY();
INSERT INTO SampleTable2 (SomeColName1, SomeColName2) VALUES (#returnValue, #OldID)
UPDATE dbo.SampleTable SET NewID = #returnValue WHERE CURRENT OF Upd_CURSOR;
FETCH NEXT FROM Upd_CURSOR INTO #OldID;
END;
CLOSE Upd_CURSOR;
DEALLOCATE Upd_CURSOR;
GO

sp_executesql and table output

I'm writing a stored procedure in SQL Server 2005, at given point I need to execute another stored procedure. This invocation is dynamic, and so i've used sp_executesql command as usual:
DECLARE #DBName varchar(255)
DECLARE #q varchar(max)
DECLARE #tempTable table(myParam1 int, -- other params)
SET #DBName = 'my_db_name'
SET q = 'insert into #tempTable exec ['+#DBName+'].[dbo].[my_procedure]'
EXEC sp_executesql #q, '#tempTable table OUTPUT', #tempTable OUTPUT
SELECT * FROM #tempTable
But I get this error:
Must declare the scalar variable "#tempTable".
As you can see that variable is declared. I've read the documentation and seems that only parameters allowed are text, ntext and image. How can I have what I need?
PS: I've found many tips for 2008 and further version, any for 2005.
Resolved, thanks to all for tips:
DECLARE #DBName varchar(255)
DECLARE #q varchar(max)
CREATE table #tempTable(myParam1 int, -- other params)
SET #DBName = 'my_db_name'
SET #q = 'insert into #tempTable exec ['+#DBName+'].[dbo].[my_procedure]'
EXEC(#q)
SELECT * FROM #tempTable
drop table #tempTable
SQL Server 2005 allows to use INSERT INTO EXEC operation (https://learn.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql?view=sqlallproducts-allversions).
You might create a table valued variable and insert result of stored procedure into this table:
DECLARE #tempTable table(myParam1 int, myParam2 int);
DECLARE #statement nvarchar(max) = 'SELECT 1,2';
INSERT INTO #tempTable EXEC sp_executesql #statement;
SELECT * FROM #tempTable;
Result:
myParam1 myParam2
----------- -----------
1 2
or you can use any other your own stored procedure:
DECLARE #tempTable table(myParam1 int, myParam2 int);
INSERT INTO #tempTable EXEC [dbo].[my_procedure];
SELECT * FROM #tempTable;
#tempTable's scope is limited to the current procedure.
You could replace the #tempTable with a global temporary table (i.e. ## table), but be very careful with the scope of that table and be sure to drop it when the procedure ends

How to return the output of stored procedure into a variable in sql server

I want to execute a stored procedure in SQL Server and assign the output to a variable (it returns a single value) ?
That depends on the nature of the information you want to return.
If it is a single integer value, you can use the return statement
create proc myproc
as
begin
return 1
end
go
declare #i int
exec #i = myproc
If you have a non integer value, or a number of scalar values, you can use output parameters
create proc myproc
#a int output,
#b varchar(50) output
as
begin
select #a = 1, #b='hello'
end
go
declare #i int, #j varchar(50)
exec myproc #i output, #j output
If you want to return a dataset, you can use insert exec
create proc myproc
as
begin
select name from sysobjects
end
go
declare #t table (name varchar(100))
insert #t (name)
exec myproc
You can even return a cursor but that's just horrid so I shan't give an example :)
You can use the return statement inside a stored procedure to return an integer status code (and only of integer type). By convention a return value of zero is used for success.
If no return is explicitly set, then the stored procedure returns zero.
CREATE PROCEDURE GetImmediateManager
#employeeID INT,
#managerID INT OUTPUT
AS
BEGIN
SELECT #managerID = ManagerID
FROM HumanResources.Employee
WHERE EmployeeID = #employeeID
if ##rowcount = 0 -- manager not found?
return 1;
END
And you call it this way:
DECLARE #return_status int;
DECLARE #managerID int;
EXEC #return_status = GetImmediateManager 2, #managerID output;
if #return_status = 1
print N'Immediate manager not found!';
else
print N'ManagerID is ' + #managerID;
go
You should use the return value for status codes only. To return data, you should use output parameters.
If you want to return a dataset, then use an output parameter of type cursor.
more on RETURN statement
Use this code, Working properly
CREATE PROCEDURE [dbo].[sp_delete_item]
#ItemId int = 0
#status bit OUT
AS
Begin
DECLARE #cnt int;
DECLARE #status int =0;
SET NOCOUNT OFF
SELECT #cnt =COUNT(Id) from ItemTransaction where ItemId = #ItemId
if(#cnt = 1)
Begin
return #status;
End
else
Begin
SET #status =1;
return #status;
End
END
Execute SP
DECLARE #statuss bit;
EXECUTE [dbo].[sp_delete_item] 6, #statuss output;
PRINT #statuss;
With the Return statement from the proc, I needed to assign the temp variable and pass it to another stored procedure. The value was getting assigned fine but when passing it as a parameter, it lost the value. I had to create a temp table and set the variable from the table (SQL 2008)
From this:
declare #anID int
exec #anID = dbo.StoredProc_Fetch #ID, #anotherID, #finalID
exec dbo.ADifferentStoredProc #anID (no value here)
To this:
declare #t table(id int)
declare #anID int
insert into #t exec dbo.StoredProc_Fetch #ID, #anotherID, #finalID
set #anID= (select Top 1 * from #t)