Save execute procedure results into a var in SQL Server 2008 - sql

I have a procedure that executes another procedure and I need to save the results into a variable.
How can I do that?
ALTER PROCEDURE sp_GetDetailsByUserId
#userId int
AS
BEGIN
SELECT
usr.FirstName, usr.LastName, usr.UserName, usr.Email
FROM
[User] usr
WHERE
usr.UserID = #userId
EXEC sp_GenerateRandomPass #userId // this result need to be inside a var
END
I am a beginner and need help.
Thank you.

you can declare a Table or you can use a Temp Table:
ALTER PROCEDURE sp_GetDetailsByUserId
#userId int
AS
BEGIN
SELECT usr.FirstName, usr.LastName, usr.UserName, usr.Email
FROM [User] usr
WHERE usr.UserID = #userId
declare #tbl table (the columns should be compatible with the result columns)
insert into #tbl
exec sp_GenerateRandomPass #userId // this result need to be inside a var
END
with temptable you can do:
ALTER PROCEDURE sp_GetDetailsByUserId
#userId int
AS
BEGIN
SELECT usr.FirstName, usr.LastName, usr.UserName, usr.Email
FROM [User] usr
WHERE usr.UserID = #userId
create table #tempTable(the columns should be compatible with the result columns)
insert into #tempTable
exec sp_GenerateRandomPass #userId // this result need to be inside a var
END

Can you change the procedure? Having output parameters would probably be best, assuming the select always returns just one row.
exec sp_GenerateRandomPass #userId, #password output
output parameters work this way:
ALTER PROCEDURE sp_GenerateRandomPass
#userId int,
#password varchar (100) output
AS
BEGIN
-- Magic happens
set #password = 'xxxx'
END
Other option is to change GenerateRandomPass to be a scalar function, you can assign value from it to a variable directly in your procedure
Also, please do not prefix your procedures with "sp_", it's intended for built in procedures.

You need to modify sp_GenerateRandomPass , Store result of query within this stored procedure to temptable. Find more about temptable.
Temp table will be accessible among stored procedures. So you can use that in sp_GetDetailsByUserId

Related

SQL Server stored procedure optionally return all records or filter based on parameter

I have a stored procedure that returns the data by passing a parameter to it, similar to:
CREATE PROCEDURE MySP (#ID VARCHAR(50))
AS
BEGIN
SET NOCOUNT ON
SELECT *
FROM mytable t
WHERE t.ID = #ID
END
I need to have this option that the stored procedure returns all records if passing no parameters, while getting specific records by passing the parameter to it.
I wonder how my stored procedure should be modified for that? I appreciate everyone's help!
Try something like (not tested):
CREATE PROCEDURE MySP (#ID VARCHAR(50))
AS
BEGIN
SET NOCOUNT ON
IF #ID = '' OR #ID IS NULL
BEGIN
SELECT *
FROM mytable t
END
ELSE
BEGIN
SELECT *
FROM mytable t
WHERE t.ID = #ID
END
END

Select Stored Procedure Outputs On-the-Fly (SQL Server)

I am trying to pass an output parameter from a stored procedure into another stored procedure. The parent needs to pass a parameter into the child.
Can I return the output on-the-fly in a select statement like this?
If not, what is a good way to approach this problem?
Stored Procedure (Child)
#uid int,
#result nvarchar(max) output
as
begin select #result = stuff((
select
'cid' = cid
from db
for xml path('')
),
1,
1,
'<'
)
return
end
Stored Procedure (Parent)
select
'id' = uid,
'result' = (exec db.dbo.table uid, #result output)
from table
Here I am trying to pass in a uid from the parents select statement, and pass it into another stored procedure, and return the result in a select.
This might be what you're after, however, the fact that you have a EXEC statement in your SELECT make me think otherwise.
CREATE PROC Child #uid int, #result nvarchar(MAX) OUTPUT AS
SELECT #result = STUFF((SELECT cid AS cid
FROM db
--Should there be a WHERE here?
FOR XML PATH(N'')),1,1,N'<');
GO
CREATE PROC Parent #uid int AS
DECLARE #result nvarchar(MAX);
EXEC Child #uid, #result OUTPUT;
SELECT #uid UID, #result AS Result;
GO
That is more of a literal copy of what you have in your question though. It might be that this is more what you're after with an inline-table function:
CREATE FUNCTION Child (#uid int)
RETURNS TABLE
AS RETURN
SELECT STUFF((SELECT cid AS cid
FROM db
--Should there be a WHERE here?
FOR XML PATH(N'')),1,1,N'<') AS cid;
GO
CREATE PROC Parent #uid int AS
SELECT #uid UID,
C.cid
FROM [Table]
CROSS APPLY dbo.Child(#uid) C
GO
Like I said in the comments, it seems we're missing a WHERE or something here.

SQL: How to make table name in stored procedure dynamic

I am pretty new to SQL Server and hope someone here can help me with this (I'm using QL Server 2008).
The following is a small procedure that works as intended.
Now I would like to use the same procedure to update multiple tables as all these tables have exactly the same column names and column formatting, the only difference is the 2nd part of the table name for which I added XXX below.
Can someone tell me how this could be made dynamic and also provide me some explanations on this ?
I cannot provide much more here as I wasn't sure about how to approach this - other than probably declaring #sql nvarchar(max) and wrapping the whole query in SET #sql = N'...' before executing it.
My stored procedure:
CREATE PROCEDURE [dbo].[Cal_UpdateTeam]
#team nvarchar(100),
#teamID int,
#notes nvarchar(1000),
#log nvarchar(100),
#admin varchar(50)
AS
BEGIN
SET NOCOUNT ON;
BEGIN
IF NOT EXISTS
(
SELECT *
FROM Cal_XXX
WHERE teamID = #teamID
)
INSERT INTO Cal_XXX
(
team,
teamID,
notes,
log,
admin
)
SELECT #team,
#teamID,
#notes,
#log,
#admin
ELSE
UPDATE Cal_XXX
SET team = #team,
teamID = #teamID,
notes = #notes,
log = #log,
admin = #admin
WHERE teamID = #teamID
END
END
Many thanks for any tips and advise on this, Mike.
you should wrap your sql query in an nvarchar and then execute that query as in the below example :
declare #sql nvarchar(max)
declare #TableName nvarchar(max)
set #TableName = 'mytable'
set #sql = 'Select * from ' + #TableName
Exec sp_executesql #sql
in SP you can use Temporary Tables fro example:
CREATE PROCEDURE SELECT_TABLE
#REQUEST_ID INT
AS
BEGIN
/*************************************
** Temporary table **
*************************************/
CREATE TABLE #SOURCE (
ID INT
, ID_PARENT INT
, NAME VARCHAR(200)
, SORT INT
..
..
)
IF #REQUEST_ID = 'YES' BEGIN
INSERT INTO #SOURCE SELECT * FROM SOURCE_A
END
ELSE BEGIN
INSERT INTO #SOURCE SELECT * FROM SOURCE_B
END
SELECT * FROM #SOURCE
.....
END
GO
in SP you can encapsulate other SPs with different table names like parameter:
CREATE PROCEDURE SELECT_FROM_TABLE_A
AS
BEGIN
SELECT * FROM SOURCE_A
END
GO
CREATE PROCEDURE SELECT_FROM_TABLE_B
AS
BEGIN
SELECT * FROM SOURCE_B
END
GO
CREATE PROCEDURE SELECT_TABLE
#REQUEST_ID INT
AS
BEGIN
/**********************************************
** Subrequest select **
**********************************************/
IF #REQUEST_ID = 'YES' BEGIN
-- Request SP fro Source A
EXEC SELECT_FROM_TABLE_A
END
ELSE
BEGIN
-- Request SP fro Source B
EXEC SELECT_FROM_TABLE_B
END
END
GO

Store values in Stored Procedure

I created a SP as "SP_SELECT"
CREATE PROCEDURE SP_SELECT #userid varchar(50)
AS
BEGIN
SELECT Dept_Id from Master where User_Id=#userid
END
GO
Now the task is I have to store the Result (i.e) Dept_Id in a variable named as "dept" in the same stored procedure itself. Help me with the query.
Do you mean this?
CREATE PROCEDURE SP_SELECT #userid varchar(50)
AS
BEGIN
DECLARE #deptid int;
SET #deptid = SELECT Dept_Id from Master where User_Id=#userid
END
RETURN #deptid
GO
You could also pass #deptid as an output parameter in sql.
But this var will only exist each time the stored proc is run on the calling function or code you will still need to store the value.
i.e.
Declare #masterdeptid int;
SET #masterdeptid = EXEC SP_Select '123';
I ain't test the sql but you get the idea
try this one
set #dept= (select Dept_Id from Master where User_Id=#userid)
and if you want return this value to front end , write below code
set #dept= (select Dept_Id from Master where User_Id=#userid)
select #dept
This could be helpful to you
CREATE PROCEDURE USP_SELECT #userid varchar(50), #Dept int output
AS
BEGIN
SELECT #Dept = Dept_Id from Master where User_Id=#userid
END
above code can be executed as
Declare #Dept int;
EXEC USP_Select '123',#Dept output
Print #Dept

SQLserver multithreaded locking with TABLOCKX

I have a table "tbluser" with 2 fields:
userid = integer (autoincrement)
user = nvarchar(100)
I have a multithreaded/multi server application that uses this table.
I want to accomplish the following:
Guarantee that field user is unique in my table
Guarantee that combination userid/user is unique in each server's memory
I have the following stored procedure:
CREATE PROCEDURE uniqueuser #user nvarchar(100) AS
BEGIN
BEGIN TRAN
DECLARE #userID int
SET nocount ON
SET #userID = (SELECT #userID FROM tbluser WITH (TABLOCKX) WHERE [user] = #user)
IF #userID <> ''
BEGIN
SELECT userID = #userID
END
ELSE
BEGIN
INSERT INTO tbluser([user]) VALUES (#user)
SELECT userID = SCOPE_IDENTITY()
END
COMMIT TRAN
END
Basically the application calls the stored procedure and provides a username as parameter.
The stored procedure either gets the userid or insert the user if it is a new user.
Am I correct to assume that the table is locked (only one server can insert/query)?
I'm sure the following advice might help someone in the future.
Instead of (TABLOCKX), try (TABLOCKX, HOLDLOCK)
or even better, if this is the only procedure in which writing to tbluser takes place, you can cut down on a whole bunch of code entirely using only TABLOCKX and no transaction via
CREATE PROCEDURE uniqueuser #user nvarchar(100)
AS
--BEGIN TRAN NOT NECESSARY!
INSERT tbluser WITH (TABLOCKX) ([user])
SELECT #user
WHERE NOT EXISTS(SELECT 1 FROM tbluser WHERE [user]=#user)
--COMMIT TRAN NOT NECESSARY!
SELECT userID FROM tbluser WHERE [user]=#user
This way, the insert statement (which automatically creates a transaction for the duration of the INSERT) is the only time you need the table lock. (Yes, I stress-tested this on two windows both with and without TABLOCKX to see how it faired before posting my message.)
If you want to guarantee that the user is unique, the only way is to a unique constraint
ALTER TABLE tbluser WITH CHECK
ADD CONSTRAINT UQ_tbluser_user UQNIUE (user);
Do not "roll your own" unique checks: it will fail.
The cached data in the server's memory conforms to the same constraint
I'd do this. Look for user first, if not found insert, handle unique error just in case. And I'd use an OUTPUT parameter
CREATE PROCEDURE uniqueuser
#user nvarchar(100)
-- ,#userid int = NULL OUTPUT
AS
SET NOCOUNT, XACT_ABORT ON;
DECLARE #userID int;
BEGIN TRY
SELECT #userID FROM tbluser WHERE [user] = #user;
IF #userID IS NULL
BEGIN
INSERT INTO tbluser([user]) VALUES (#user);
SELECT userID = SCOPE_IDENTITY() ;
END
END TRY
BEGIN CATCH
-- test for a concurrent call that just inserted before we did
IF ERROR_NUMBER() = 2627
SELECT #userID FROM tbluser WHERE [user] = #user;
ELSE
-- do some error handling
END CATCH
-- I prefer output parameter for this SELECT #userID AS UserID
GO
Edit: why TABLOCKX fails...
You only lock the table for the duration of the SELECT.
A 2nd process running concurrently will starting reading the table after the lock is released by process 1
Both processes can have #userID IS NULL because process 1 has not yet executed the INSERT
Process 2 gets an error when it INSERTS
This happens because TABLOCKX modifies lock isolation and granularity, not duration.
Edit 2: for SQL Server 2000
CREATE PROCEDURE uniqueuser
#user nvarchar(100)
-- ,#userid int = NULL OUTPUT
AS
SET NOCOUNT, XACT_ABORT ON;
DECLARE #userID int;
SELECT #userID FROM tbluser WHERE [user] = #user;
IF #userID IS NULL
BEGIN
INSERT INTO tbluser([user]) VALUES (#user);
IF ##ERROR = 2627
SELECT #userID FROM tbluser WHERE [user] = #user;
ELSE
RAISERROR ('the fan needs cleaning', 16, 1);
SELECT userID = SCOPE_IDENTITY();
END
GO