This question already has answers here:
TSQL: Call a stored procedure from another stored procedure and read the result
(5 answers)
Closed 4 years ago.
I am creating stored procedures (sprocs) to perform operations on my tables in my database. I have a sproc SubjectExists that returns '1' if the subject name entered is in the subject table and returns '0' if it does not exist.
CREATE PROCEDURE SubjectExists #SubjName varhcar(20)
AS
SELECT CASE WHEN EXISTS(
SELECT *
FROM Subject
WHERE Subject_Name = #SubjName
)
THEN CAST (1 AS BIT)
ELSE CAST (0 AS BIT)
END
I am now making another sproc that deletes a subject from the table. I want to make this sproc such that it uses SubjectExists and if the output of it is a 1 (i.e. the subject does exist) then it deletes the subject and if the output from SubjectExists is 0, it does nothing.
How would I go about doing this?
I have tried experimenting with the below but no luck so far.
CREATE PROCEDURE DeleteSubject #SubjName varchar(20)
AS
IF (EXEC StudentExists Bob)
DELETE FROM Subject
WHERE Subject_Name = #SubjName;
Can anyone please guide me as to how I would do this.
Thanks
At first, your stored procedure should return value:
CREATE PROCEDURE SubjectExists #SubjName varchar(20)
AS
BEGIN
DECLARE #ReturnValue int
SELECT #ReturnValue = CASE WHEN EXISTS(
SELECT *
FROM Subject
WHERE Subject_Name = #SubjName
)
THEN CAST (1 AS BIT)
ELSE CAST (0 AS BIT)
END
RETURN #ReturnValue
END
Then you can declare some table to store results of your stored procedure and if it is eligible, then run your code
DECLARE #FooValue int;
EXEC #FooValue = SubjectExists 'helloWorld!:)'
IF #FooValue = 1
BEGIN
DELETE FROM Subject
WHERE Subject_Name = #SubjName;
END
You need to get the return value from the stored procedure like this-
DECLARE #returnvalue INT
EXEC #returnvalue = StudentExists Bob
and then you can make your If condition.
Related
I have a stored procedure A on server 1 that takes 2 parameters from the user, and then using a linked server (ew), pulls in the results (a table) from server 2.
ALTER PROCEDURE [DW].[StoredProcA]
#InvFromDate date OUTPUT,
#InvToDate date OUTPUT
AS
WITH CTE_Labor AS
(
SELECT blabla
FROM LinkedServer.Database.schema.table
<lots more ctes, etc.>
For performance, I'd like to instead have a stored procedure A still accept the 2 parameters, but then pass them on to stored procedure B that sits on Server 2, and return those results back to the user.
Say - I can put the stored procedure on server 2, and call it from Server 1
DECLARE #return_value int
EXEC #return_value = [LinkedServer].[DB].[Schema].[StoredProcB]
#InvFromDate = '2022-10-01',
#InvToDate = '2022-10-31'
That works.
But I'm not clear on the syntax to do the above, but have those 2 parameters be entered by the user in stored procedure 1.
Clearly this attempt is wrong:
ALTER PROCEDURE dbo.StoredProc1
#InvFromDate DATE,
#InvToDate DATE
AS
BEGIN
DECLARE #return_value int;
EXEC #return_value = [LinkedServer].[DB].[Schema].[StoredProcB]
#InvFromDate = #InvFromDate,
#InvToDate = #InvToDate;
RETURN #return_value;
END
Edit: Maybe this attempt isn't wrong.
It works when I right click and run the stored procedure, returning both the desired table and Return Value = 0. It just doesn't work when I point our front-end GUI at it. But that might not be a question for here.
Since you are already using a linked server you could utilise this openquery approach Insert results of a stored procedure into a temporary table
Noting the following:
OPENQUERY/ linked servers are generally bad but I'm sure you're all over this
parameter string concatenation is bad
Your wrapper proc has output parameters but I don't see any reason for it... so I've removed them. See if it makes a difference.
--
ALTER PROCEDURE [DW].[StoredProcA]
#InvFromDate date,
#InvToDate date
AS
DECLARE #sql VARCHAR(4000)
SET #sql = 'EXEC [DB].[Schema].[StoredProcB] #InvFromDate = ''' + FORMAT(#InvFromDate + 'yyyy-MM-dd') + ''',#InvToDate = ''' + FORMAT(#InvToDate,'yyy-MM-dd') + ''''
PRINT(#sql) -- for degbugging cause this never works first time
SELECT *
INTO #tmpTable
FROM OPENQUERY([LinkedServer], #SQL)
SELECT * FROM #tmpTable
Got it.
1.) For this method, have to go into the Linked Server, and set [Enable Promotion of Distribution Transaction] = FALSE.
2.) Syntax
Alter proc [dbo].[999_Test]
#InvFromDate date
,#InvToDate date
as
IF OBJECT_ID('tempdb..#tmpbus') IS NOT NULL drop table #tmpbus;
CREATE TABLE #tmpBus
(
Column 1 (datatype),
Column 2 (datatype),
etc. )
INSERT INTO #tmpBus
EXEC [LinkedServer].[DB].Schema.[StoredProcInLinkedServerO]
#InvFromDate,
#InvToDate;
select *
from #tmpBus
GO
This question already has answers here:
T-SQL stored procedure that accepts multiple Id values
(5 answers)
Closed 4 years ago.
I have got a stored procedure which has five parameters. I want to include them in where clause as follows
If parameter is not null then include it in query as an IN clause
That is, parameter value can be like 'Test' or 'Test,Best' etc. I'm converting this comma seperated values into table using function in SQL.
I tried to use COALESCE(#test,test_column) = test_column but i'm unable to include IN clause here (What if #test = 'Test,Best').
So, i want to do something like mentioned below
DECLARE #param varchar(max) = 'Test,Best';
Select * from table where CASE when #param is not null then table.column in (#param)
Any suggestions please.
I've adapted this answer to your requirements.
First create User-Defined Table type:
CREATE TYPE dbo.ParamsList
AS TABLE
(
Param varchar(50)
);
Then just use this parameter and other parameters in your stored procedures:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List AS dbo.ParamsList READONLY
, #param1 INT = NULL
, #param2 NVARCHAR(150) = NULL
, #param3 NVARCHAR(150) = NULL
, #param4 NVARCHAR(150) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT
*
FROM YourTable
WHERE YourColumn NOT IN (SELECT Param FROM #List)
END
GO
When exactly do we use stored procedures with output parameters and when do we use stored procedures without parameters?
I base my question on an example:
Stored procedure with output parameter
CREATE PROCEDURE uspGetContactsCountByCity
#City nvarchar(60),
#ContactsCount int OUT
AS
BEGIN
SELECT #ContactsCount = COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing
DECLARE #ContactsTotal INT
EXEC uspGetContactsCountByCity #ContactsCount = #ContactsTotal OUT, #city = 'Berlin'
SELECT #ContactsTotal
Results: 2
Stored procedure without output parameter
CREATE PROCEDURE uspGetContactsCountByCity2
#City nvarchar(60)
AS
BEGIN
SELECT COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing:
EXEC uspGetContactsCountByCity2 #city = 'Berlin'
Results: 2
Both procedures return the same result, in same form, so what's the difference?
Basically, the result you're seeing is actually the result of your SELECT at the end of the procedure, which is doing the same thing.
Please take a look at this documentation:
If you specify the OUTPUT keyword for a parameter in the procedure definition, the stored procedure can return the current value of the parameter to the calling program when the stored procedure exits. To save the value of the parameter in a variable that can be used in the calling program, the calling program must use the OUTPUT keyword when executing the stored procedure.
So basically if you would like your stored procedure to just return just a value instead of a data set, you could use the output parameter. For example, let's take the procedures you have given as an example. They both do the same thing, this is why you got the same result. But what about changing a little bit in the first procedure that has the output parameter.
Here's an example:
create table OutputParameter (
ParaName varchar(100)
)
insert into OutputParameter values ('one'), ('two'),('three'),('one')
CREATE PROCEDURE AllDataAndCountWhereOne
#name nvarchar(60),
#count int OUT
as
Begin
SELECT #count = COUNT(*) from OutputParameter
Where ParaName = #name
select Distinct(ParaName) from OutputParameter
End
Declare #TotalCount int
Exec AllDataAndCountWhereOne #count = #TotalCount OUT, #name = 'One'
Select #TotalCount
With this example, you are getting all the distinct stored data in the table, plus getting the count of a given name.
ParaName
--------------------
one
three
two
(3 row(s) affected)
-----------
2
(1 row(s) affected)
This is one way of using the output parameter. You got both the distinct data and the count you wanted without doing extra query after getting the initial data set.
At the end, to answer your question:
Both procedures gives us the same result, in same form, so what's the difference?
You didn't make a difference in your own results, this is why you didn't really notice the difference.
Other Examples:
You could use the OUT parameter in other kinds of procedures. Let's assume that your stored procedure doesn't return anything, it's more like a command to the DB, but you still want a kind of message back, or more specifically a value. Take these two examples:
CREATE PROCEDURE InsertDbAndGetLastInsertedId
--This procedure will insert your name in the database, and return as output parameter the last inserted ID.
#name nvarchar(60),
#LastId int OUT
as
Begin
insert into OutputParameterWithId values (#name);
SELECT #LastId = SCOPE_IDENTITY()
End
or:
CREATE PROCEDURE InsertIntoDbUnlessSomeLogicFails
--This procedure will only insert into the db if name does exist, but there's no more than 5 of it
#name nvarchar(60),
#ErrorMessage varchar(100) OUT
as
Begin
set #ErrorMessage = ''
if ((select count(*) from OutputParameterWithId) = 0)
begin
set #ErrorMessage = 'Name Does Not Exist'
return
end
if ((select count(*) from OutputParameterWithId) = 5)
begin
set #ErrorMessage = 'Already have five'
return
end
insert into OutputParameterWithId values (#name);
End
These are just dummy examples, but just to make the idea more clear.
An example, based on yours would be if you introduced paging to the query.
So the result set is constrained to 10 items, and you use a total count out parameter to drive paging on a grid on screen.
Answer from ozz regarding paging does not make sense because there is no input param that implements a contraint on the number of records returned.
However, to answer the question... the results returned by these stored procedures are not the same. The first returns the record count of contacts in given city in the out param ContactsCount. While the count may also be recieved in the second implement through examining the reader.Rows.Count, the actual records are also made a available. In the first, no records are returned - only the count.
I am writing code on entity framework 6.0, linq on asp.net, sql server platform.
I've written a stored procedure which supposed to return an output value (0 or 1)
Firstly I wrote SP by using output parameter as follows:
ALTER proc [dbo].[checkUser]
(
#oNo int,
#pw varchar(50),
#val int output
)
as
begin
if EXISTS (select * from Users where #oNo=sNo and #pw=password)
begin
set #val=1
end
if not exists(select * from Users where #oNo=sNo and #pw=password)
begin
set #val=0
end
end
Didnt work. It returned -1. Then I changed SP like this:
ALTER proc [dbo].[checkUser]
(
#oNo int,
#pw varchar(50)
)
as
begin
if EXISTS (select * from Users where #oNo=sNo and #pw=password)
begin
return 1
end
else
begin
return 0
end
end
Each ways stored procedure returns only -1
Can you help me please, where am i doing wrong?
Try to replace "return" by "select".
if EXISTS (select * from Users where #oNo=sNo and #pw=password)
begin
select 1
end
else
begin
select 0
end
Be gentle, I'm a SQL newbie. I have a table named autonumber_settings like this:
Prefix | AutoNumber
SO | 112320
CA | 3542
A whenever a new sales line is created, a stored procedure is called that reads the current autonumber value from the 'SO' row, then increments the number, updates that same row, and return the number back from the stored procedure. The stored procedure is below:
ALTER PROCEDURE [dbo].[GetAutoNumber]
(
#type nvarchar(50) ,
#out nvarchar(50) = '' OUTPUT
)
as
set nocount on
declare #currentvalue nvarchar(50)
declare #prefix nvarchar(10)
if exists (select * from autonumber_settings where lower(autonumber_type) = lower(#type))
begin
select #prefix = isnull(autonumber_prefix,''),#currentvalue=autonumber_currentvalue
from autonumber_settings
where lower(autonumber_type) = lower(#type)
set #currentvalue = #currentvalue + 1
update dbo.autonumber_settings set autonumber_currentvalue = #currentvalue where lower(autonumber_type) = lower(#type)
set #out = cast(#prefix as nvarchar(10)) + cast(#currentvalue as nvarchar(50))
select #out as value
end
else
select '' as value
Now, there is another procedure that accesses the same table that duplicates orders, copying both the header and the lines. On occasion, the duplication results in duplicate line numbers. Here is a piece of that procedure:
BEGIN TRAN
IF exists
(
SELECT *
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
)
BEGIN
SELECT
#prefix = ISNULL(autonumber_prefix,'')
,#current_value=CAST (autonumber_currentvalue AS INTEGER)
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
SET #new_auto_number = #current_value + #number_of_lines
UPDATE dbo.autonumber_settings
SET autonumber_currentvalue = #new_auto_number
WHERE autonumber_type = 'SalesOrderDetail'
END
COMMIT TRAN
Any ideas on why the two procedures don't seem to play well together, occasionally giving the same line numbers created from scratch as lines created by duplication.
This is a race condition or your autonumber assignment. Two executions have the potential to read out the same value before a new one is written back to the database.
The best way to fix this is to use an identity column and let SQL server handle the autonumber assignments.
Barring that you could use sp_getapplock to serialize your access to autonumber_settings.
You could use repeatable read on the selects. That will lock the row and block the other procedure's select until you update the value and commit.
Insert WITH (REPEATABLEREAD,ROWLOCK) after the from clause for each select.