Use stored procedure output parameter - sql

ALTER PROCEDURE dbo.StoredProcedure8
#emp_code bigint,
#co_id bigint,
#p decimal(8,2) output
AS
SELECT #p = (select sum(tran_value) from emp_ded_ben_trans where emp_code=#emp_code and co_id=#co_id and period_flg=2 and tax_flg=0)
RETURN

To call that sproc and retrieve the output parameter, you do (e.g.):
DECLARE #p DECIMAL(8,2)
EXECUTE dbo.StoredProcedure8 123, 456, #p OUTPUT
-- #p now contains the output value
Update:
You don't need to use RETURN - you are right in that a RETURN can only return an INTEGER. But a return value is different to an OUTPUT parameter which is what you are actually using.
i.e. to get a RETURN value from a sproc, is different syntax:
DECLARE #Result INTEGER
EXECUTE #Result = SomeSproc

Stored procedures aren't made to "return values" - that's what you have stored functions for.
CREATE FUNCTION dbo.CalculateSomething
(#emp_code bigint, #co_id bigint)
RETURNS DECIMAL(8, 2)
AS BEGIN
RETURN
(SELECT SUM(tran_value)
FROM dbo.emp_ded_ben_trans
WHERE
emp_code = #emp_code AND co_id = #co_id
AND period_flg = 2 AND tax_flg = 0)
END
You can then call this stored function like this:
SELECT dbo.CalculateSomething(value_for_emp_code, value_for_co_id)
and get back a DECIMAL(8,2) from the calculation.
Stored procedures will return the number of rows affected by their operation - an INT.
If you need to return a value from a stored proc, you need to use the OUTPUT parameter type and use the technique that AdaTheDev shows - you need to grab the output value into a variable.

First you can use not a Stored Procedure by a Function if you have to return a single value basing on input parameters
If your sp return decimal when you need integer - just cast: SELECT (CAST #d AS INT) but this is very dangerous (possible type overflow)

If your Column tran_value is of Decimal Type, the #p will have decimal values after you run the query...
Create Table #test
(ID1 Int,
ID2 Decimal(8,2)
)
Insert into #test Values (1,1.1)
Insert into #test Values (2,2.2)
Insert into #test Values (3,3.3)
Declare #p Decimal(8,2), #intp int
Select #intp = Sum(ID1), #p = Sum(ID2) from #test
Select #intp as IntegerSum, #p as DecimalSum
Drop Table #test
Output
IntegerSum DecimalSum
----------- ---------------------------------------
6 6.60
Note : You need not have to do anything specific to return the value from Stored Procedure through output parameter... Just assign the value to output parameter inside your SP, it will be returned to the caller automatically.
This means your SP is correct even without the return statement

Related

How to check only the first value of the row returned from stored procedure in a SQL query

If I have a stored procedure like this:
get_my_dep(empNum)
and it returns one row ex:
call get_my_dep(567);
dep_code dep_year dep_name
66 2017 HR
How can I check only the first value of the row (dep_code) in my query like this:
SELECT *
FROM rmcandidate a INNER JOIN task b
ON a.task_code = b.task_code
WHERE get_my_dep(emp_num) != 0 -- here I want to check only the dep_code
AND b.active_flag = 1
Presumably the stored procedure is defined as returning multiple values as in:
create procedure get_my_dep(emp_num int)
returning int as dep_code, int as dep_year, char(8) as dep_name;
In this case you could create a wrapper procedure that returns only one of the values and then use that in the WHERE clause. For example:
create procedure get_my_dep_code(emp_num int)
returning int as dep_code;
define dc, dy int;
define dn char(8);
execute procedure get_my_dep(emp_num) into dc, dy, dn;
return dc;
end procedure;
An alternative could be to define the procedure to return a row type. For example:
create row type dep_code_t(dep_code int, dep_year int, dep_name char(8));
create procedure get_my_dep(emp_num int)
returning dep_code_t;
define dc, dy int;
define dn char(8);
...
return row(dc, dy, dn)::dep_code_t;
end procedure;
It is then possible to directly reference an element of the returned row type in a WHERE clause as in:
WHERE get_my_dep(emp_num).dep_code != 0
You can try using a virtual table:
SELECT
*
FROM
rmcandidate AS a
INNER JOIN task AS b
ON
a.task_code = b.task_code
WHERE
b.active_flag = 1
AND 0 !=
(
SELECT
vt1.dep_code
FROM
TABLE (get_my_dep(emp_num)) AS vt1 (dep_code, dep_year, dep_name)
)
;
This was tested on Informix 12.10 .

Array as input variable in Stored Procedure [duplicate]

I have a list ClaimData in C# and it has three items Date, Type and Description
There can be multiple rows in this as below,
ClaimData
Date Type Description
01/02/2012 "Medical" "Its a medical"
05/02/2013 "Theft" "Its a Theft"
01/02/2014 "Test" "Its a Test"
I want to pass this whole data to a stored procedure in one go to the sql server, so that I can reduce the database hits. I have written stored procedure which can iterate through this list and insert them in a table.
How to achieve by manipulating the list object could be passed to the stored procedure as a parameter?
You will need to do a couple of things to get this going, since your parameter is getting multiple values you need to create a Table Type and make your store procedure accept a parameter of that type.
Since you are passing a TABLE as a parameter you will need to create a TABLE TYPE something as follows
TABLE TYPE
CREATE TYPE dbo.ClaimData AS TABLE
(
[Date] DATE
[Type] VARCHAR(50)
[Description] VARCHAR(100)
)
GO
Stored Procedure to Accept That Type Param
CREATE PROCEDURE mainValues
#TableParam ClaimData READONLY --<-- Accepts a parameter of that type
AS -- Note it is ReadOnly
BEGIN
SET NOCOUNT ON;
--Temp table to store the passed values
-- since the passed parameter is only Read only and you
-- cannot make any changes to the parameter so if you need to
-- manipulate the data inside parameter you will need to get it
-- into a Table vaiable.
-- Declare a Table variable
DECLARE #tmp_values table(
[Date] DATE
[Type] VARCHAR(50)
[Description] VARCHAR(100)
);
--Get values into that Table variable
INSERT INTO #tmp_values ([Date],[Type],[Description])
SELECT [Date],[Type],[Description] FROM #TableParam
-- Do other cool stuff with your passed data
SELECT * FROM #tmp_values --<-- For testing purpose
END
EXECUTE PROC
Declare a variable of that type and populate it with your values.
DECLARE #Table ClaimData( --<-- Declare a variable of your type
[Date] DATE
[Type] VARCHAR(50)
[Description] VARCHAR(100)
);
-- Populate the variable
INSERT INTO #Table ([Date],[Type],[Description])
SELECT [Date],[Type],[Description] FROM Source_Table
EXECUTE mainValues #Table --<-- Stored Procedure Executed
I sent all three column as a string using string builder and delimeter '|'
DateString = '01/02/2012|05/02/2013|01/02/2014'
TypeString = 'Medical|Theft|Test'
DescString = "Its a medical|..."
On database side I used a function to delimit these strings and inserted all these values in a temp table. This solved my problem.

Returning or outputting a #tableVariable in SQL

Is it possible to return or output a #tableVariable in SQL Server?
For example for the following stored procedure, how do I return the #TSV table variable?
ALTER PROCEDURE MyStoredProdecure
#Parameter1 INT,
#Parameter2 INT
AS
BEGIN
DECLARE #TSV TABLE
(
Transition_Set_Variable_ID INT,
Passed BIT
)
INSERT INTO #TSV
{ some data }
END
You cannot do it directly. Table variables are valid for READONLY input.
If you have no other data being returned from the stored procedure, you can select from the #TSV at the end and have the caller capture the output, e.g.
ALTER PROCEDURE MyStoredProdecure
#Parameter1 INT,
#Parameter2 INT
AS
BEGIN
DECLARE #TSV TABLE
(
Transition_Set_Variable_ID INT,
Passed BIT
)
INSERT INTO #TSV
{ some data }
SELECT * FROM #TSV
END
Caller
DECLARE #outerTSV TABLE
(
Transition_Set_Variable_ID INT,
Passed BIT
);
insert into #outerTSV
exec MyStoredProdecure 1, 2;
Alternatively, if the SP is really as simple as you showed, turn it into a table valued function instead.
No, but you can write a table valued function that returns a table.
create function MyTVF
#Parameter1 INT,
#Parameter2 INT
returns #tsv table
(
Transition_Set_Variable_ID INT,
Passed BIT
)
AS
BEGIN
INSERT INTO #TSV
{ some data }
return
END
Table Valued Parameters can only be used for input only, not output.
Depending on what your end goal is, here are some options:
change the sproc to a table-valued function to return a TABLE, that can then be used inline in another statement
simply SELECT the data from the #TSV table var at the end of your sproc
return an XML OUTPUT parameter (get a grubby feeling suggesting this, but just to highlight one way to return multiple rows actually using an OUTPUT parameter)
If you go for a Table Valued Function, ideally create an inline one if it is simple as it looks in your case:
e.g.
CREATE FUNCTION dbo.Func()
RETURNS TABLE
AS
RETURN
(
SELECT Something
FROM Somewhere
WHERE x = 1
)

sql function in stored procedure

I have a scalar function for formatting the text into uppercase and remove leading, trailing spaces etc. During an insert operation in a stored procedure, I'm invoking the function like this:
insert into tablename(col1,col2) values ( dbo.function_name(value1),value2)
Here the col1 is NOT NULL. The above statement is throwing an error "Attempting to set a non-NULL-able column's value to NULL". But if you run the function alone, it return the value properly.
Please help explain where I'm going wrong.
insert into table(Col1,Col2)
values (isnull(dbo.function_name(value1),''),value2)
How about you try placing the value in a variable first and to help when you debug it.
DECLARE #val1 varchar(100)
SET #val1 = dbo.function_name(value1)
PRINT #val1 -- print it to see if we get what we expect.
SET #val1 = isnull(#val1,'') -- We can also check for null
insert into tablename(col1,col2) values ( #val1,value2)
This will at least confirm what is happening during execution and you can confirm the function is operating as you expect.
Could you add a short but complete example that actually demonstrates the problem to your question. The following does not produce any errors, but I'm having to guess in a lot of places:
create table tablename (
col1 varchar(20) not null,
col2 varchar(10) null
)
go
create function dbo.function_name (
#InVal varchar(20)
)
returns varchar(20)
as
begin
return UPPER(LTRIM(RTRIM(#InVal)))
end
go
create procedure dbo.procname
#value1 varchar(20),
#value2 varchar(10)
as
insert into tablename(col1,col2) values ( dbo.function_name(#value1),#value2)
go
exec dbo.procname ' abc ','def'
go
select * from tablename
Result:
col1 col2
ABC def

STORED PROCEDURE Calculations & performance improvements

I currently have the following stored procedure;
CREATE PROCEDURE web.insertNewCampaign
(
#tmp_Id BIGINT,
#tmp_Title VARCHAR(100),
#tmp_Content VARCHAR(8000),
#tmp_Pledge DECIMAL(7,2),
--#tmp_Recipients BIGINT,
#tmp_Date DATETIME,
#tmp_Private BIT,
#tmp_Template BIGINT,
#tmp_AddyBook BIGINT
)
AS
declare #recipients BIGINT
declare #tmp_IDENTITY BIGINT
declare #fave BIGINT
declare #allocation VARCHAR(50)
--insert campaign data
BEGIN TRAN
SELECT #recipients = addMaster_NoRecipients FROM tbl_AddressBookMaster
WHERE addMaster_UserId = #tmp_Id AND addMaster_Key = #tmp_AddyBook;
INSERT INTO TBL_CAMPAIGNS ([campaign_MemberId], [campaign_Title], [campaign_Content], [campaign_Pledge], [campaign_Date], [campaign_Private], [campaign_Template], [campaign_AddressBook], [campaign_Recipients])
VALUES (#tmp_Id, #tmp_Title, #tmp_Content, #tmp_Pledge, #tmp_Date, #tmp_Private, #tmp_Template, #tmp_AddyBook, #recipients)
SELECT #tmp_IDENTITY = SCOPE_IDENTITY() --this returns the newly added IDENTITY ID
COMMIT
......
So i have 2 questions:
1) How do i divide #tmp_Pledge by #recipients to give #allocation eg:(#allocation = #tmp_Pledge / #recipients)
2) Is it possible to compound these statements into a more efficient statement(s) with #allocation effectively being inserted as a value into the column [campaign_RecipShare], and reducing the need for these declared variables?
Many Thanks for any help you can offer for either question.
;-)
After the first select, you can do this to set #allocation:
set #allocation = #tmp_pledge / #recepients
As for making it more efficient, it's already fairly efficient--you won't go through any less steps, but you can condense the code a bit:
INSERT INTO TBL_CAMPAIGNS (
[campaign_MemberId], [campaign_Title], [campaign_Content],
[campaign_Pledge], [campaign_Date], [campaign_Private],
[campaign_Template], [campaign_AddressBook], [campaign_Recipients],
[capmain_RecipShare])
SELECT
#tmp_Id, #tmp_Title, #tmp_Content,
#tmp_Pledge, #tmp_Date, #tmp_Private,
#tmp_Template, #tmp_AddyBook, addMaster_NoRecipients,
#tmp_Pledge / addMaster_NoReceipients as Allocation
FROM
tbl_AddressBookMaster
WHERE
addMaster_UserId = #tmp_Id
AND addMaster_Key = #tmp_AddyBook
SELECT #tmp_IDENTITY = SCOPE_IDENTITY() --this returns the newly added IDENTITY ID
This also removes the need for you calculating the #allocation member outside of the insert statement.
1) #tmp_pledge / #recepients - I'll assume allocation is a numeric field of some form in TBL_CAMPAIGNS holding a number in varchar is not a good idea.
2) You just need to build a select that returns all the values from the other table and the parameters matching the columns to insert into.
insert into TBL_CAMPAIGNS ([campaign_MemberId], [campaign_Title], [campaign_Content], [campaign_Pledge], [campaign_Date], [campaign_Private], [campaign_Template], [campaign_AddressBook], [campaign_Recipients], [campaign_allocation)
select #tmp_Id, #tmp_Title, #tmp_Content, #tmp_Pledge, #tmp_Date, #tmp_Private, #tmp_Template, #tmp_AddyBook, addMaster_NoRecipients, #tmp_pledge / addMaster_NoRecipients
FROM FROM tbl_AddressBookMaster
WHERE addMaster_UserId = #tmp_Id AND addMaster_Key = #tmp_AddyBook;
SELECT #tmp_IDENTITY = SCOPE_IDENTITY() --this returns the newly added IDENTITY ID
set #allocation = #tmp_pledge / (#recepients* 1.0)
You want to do that because othewise you will run into integer math and the result will round to an integer.