Replacing function call with procedure execution in sql - sql

I had a function called dbo.Match.It was an inline TVF that I replaced with a procedure called dbo.Match that has a select statement at its end to select rows from a table so that I can direct the results of select query when I execute dbo.Match to a temporary table called #Temp.
Now if it was a function, I was using this query :
if #MotherFN is not null
begin
SELECT #constVal = FunctionWeight
FROM dbo.FunctionWeights
WHERE FunctionWeights.FunctionId = 20;
INSERT INTO #Temp2
(RowNumber,ValFromUser,ColumnName,ValFromFunc,FuncWeight,percentage)
SELECT RowId,
#MotherFN ,
'mothersfirstname'
,PercentMatch,
#constVal,
PercentMatch * #constVal
FROM dbo.Match(#MotherFN)
end
Now, I need to execute dbo.Match procedure instead of dbo.Match function.How I may make this execution call and insert data in #Temp table like I was doing with function call ?
Problem : Calculating PercentMatch * #constVal and inserting in #Temp in same step efficiently. Procedure dbo.Match would return rowId and PercentMatch only. I need to insert values of RowId and PercentMatch in #Temp along with value of #constVal and a value for result of multiplication of PercentMatch and #constval

I would make the procedure accept these following parameters
#MotherFN , #constVal
And do the following inside the procedure , in select statement that returns the procedure's result set.
SELECT RowId,
#MotherFN , --<-- In proc definition
'mothersfirstname'
,PercentMatch,
#constVal, --<-- In proc definition
PercentMatch * #constVal --<-- In proc definition
And for insert simply do
INSERT INTO #TemP (RowNumber,ValFromUser,ColumnName
,ValFromFunc,FuncWeight,percentage)
Exec dbo.Match(#MotherFN , #constVal)

You options are more limited with a procedure.
You can use insert into ... exec ... to insert the results of the procedure into a temporary table, but you can't really combine it with another query. (Well you could use openrowset with dynamic SQL, but that will get nasty very quickly).
For example something like:
if #MotherFN is not null
begin
select
#constVal = FunctionWeight
from
dbo.FunctionWeights
where
FunctionWeights.FunctionId = 20;
insert into #Temp2 (
RowId, ColumnName, ValFromFunc
) exec
dbo.Match(#MotherFN);
update
#Temp2
set
ValFromUser = #MotherFN,
FuncWeight = #constVal,
percentage = PercentMatch * #constVal;
end;

Related

How to assign an output of a stored procedure that is nested in a stored procedure?

I have a stored procedure that has a nested stored procedure that is executed when the parent stored procedure is executed.
Can the output of the nested stored procedure be assigned to a #variable and the output in a select statement?
EXEC #bat_key = [dbo].[client_icc_set_batch] - I can see the output here but would also like to include the output in a SELECT statement.
SELECT 'return_key' = #bat_key
I would just do it like this:
DECLARE #bat_key INT
CREATE TABLE #tmp (bat_key INT)
INSERT #tmp
EXEC [dbo].[client_icc_set_batch];
SET #bat_key = (
SELECT TOP 1 bat_key
FROM #tmp
order by bat_key DESC
);
SELECT 'return_key' + '=' + CONVERT(VARCHAR, #bat_key)
DROP TABLE #tmp

Switch case with storing results into same table in SQL

I want to store the results into table with same name as per the condition. How to achieve the same ? Following is the code:
While executing it throws error that #a already exists.
IF #Input ='1'
BEGIN
drop #a
SELECT *
INTO #a
FROM table1
END;
ELSE IF #Input ='2'
BEGIN
drop #a
SELECT *
INTO #a
FROM table2
END;
You can use this solution using a global temporary table (maybe not the best / safest solution). The statements get executed with EXECUTE:
DECLARE #Input VARCHAR(20) = '1'
IF OBJECT_ID('tempdb..##a') IS NOT NULL
BEGIN
DROP TABLE ##a
END
IF #Input = '1'
EXEC ('SELECT * INTO ##a FROM table1;')
ELSE IF #Input = '2'
EXEC ('SELECT * INTO ##a FROM table2;')
-- you can implement steps here to create a local temporary table.
-- see: https://stackoverflow.com/questions/9534990/tsql-select-into-temp-table-from-dynamic-sql
SELECT * FROM ##a
Also have a look at this question: TSQL select into Temp table from dynamic sql. There is also described how you can get the data as local temporary table in two different ways (using a global temporary table or a view).
The problem using the EXECUTE function is leaving the scope.
try this
if object_id('tempdb..#a') is not null
drop table #a
IF #Input ='1'
BEGIN
SELECT *
INTO #a
FROM table1
END;
ELSE IF #Input ='2'
BEGIN
SELECT *
INTO #a
FROM table2
END;

how to insert cases into a table based on a parameter without duplicating the main select query?

I have a insert statement in sql server 2008 like below:
INSERT INTO MYTABLE
SELECT Id,Name,Date
FROM #temp
...joins...
where ...conditions...
I need to add a parameter to the code, and based on the parameter I will decide which table the output data should be inserted into. Check below:
declare #checkValue bit;
if (#checkValue = 1)
begin
INSERT INTO MYTABLE
SELECT Id,Name,Date
FROM #temp
...joins...
where ...conditions...
end
else
begin
INSERT INTO MY_OTHER_TABLE
SELECT Id,Name,Date
FROM #temp
...joins...
where ...conditions...
end
I handled the situation like above for now, however the main query is pretty long and I do not want to duplicate it, it does not look professional to me. I am looking for a better way to deal with such an issue. Any help or advice should be appreciated. Thanks.
You could use dynamic SQL (evil :), like so:
declare #cmd varchar(max) = '
INSERT INTO ' + #tableName + '
SELECT ...
';
execute (#cmd);
Or you create stored procedures (one statically INSERTs to table A, another one into table B >> code duplication) which are called depending on #checkValue, or a combination of both like here:
Stored procedure to insert values into dynamic table
create SP:
CREATE PROCEDURE ExampleSelect
AS
SELECT Id,Name,Date
FROM #temp
...joins...
where ...conditions...
GO
use insert..exec to insert data:
declare #checkValue bit;
if (#checkValue = 1)
begin
INSERT INTO MYTABLE
EXEC ExampleSelect
end
else
begin
INSERT INTO MY_OTHER_TABLE
EXEC ExampleSelect
end

converting multiline Table valued function to inline in SQL

Considering the performance issues, I wanted to make my multiline Table valued function, an inline TVF.
Here is the sample code for Multiline TVF:
CREATE FUNCTION MatchAptNumber (#AptNumberFromUser nvarchar(20))
RETURNS #MatchedData Table
(
RowNumber int null ,
PercentMatch int null
)
AS
Begin
Insert into #MatchedData(RowNumber) select dbo.Patients.Rowid from dbo.Patients where dbo.Patients.Aptnumber = #AptNumberFromUser
update #MatchedData set PercentMatch= 100
RETURN;
END;
Go
Here is how I use it:
select #constVal = FunctionWeight from dbo.FunctionWeights where FunctionWeights.FunctionName = 'MatchAptNumber';
INSERT INTO #Temp2(RowNumber, ValFromFunc, FuncWeight, percentage)
SELECT RowNumber, PercentMatch, #constVal, PercentMatch * #constVal
from dbo.MatchAptNumber(#Aptnumber);
Is it possible to convert it into an inline TVF and use it as mentioned above? I do know the syntactic differences between two but not sure how it be possible to use it the same way? Can I get some pointers on same?
You can get the '100' as a constant in the SELECT so the function becomes;
CREATE FUNCTION MatchAptNumber (#AptNumberFromUser nvarchar(20))
RETURNS TABLE AS RETURN
SELECT
p.Rowid AS RowNumber ,
CAST(100 AS INT) AS PercentMatch
FROM
dbo.Patients p
WHERE
p.Aptnumber = #AptNumberFromUser
GO

SQL server stored procedure return a table

I have a stored procedure that takes in two parameters. I can execute it successfully in Server Management Studio. It shows me the results which are as I expect. However it also returns a Return Value.
It has added this line,
SELECT 'Return Value' = #return_value
I would like the stored procedure to return the table it shows me in the results not the return value as I am calling this stored procedure from MATLAB and all it returns is true or false.
Do I need to specify in my stored procedure what it should return? If so how do I specify a table of 4 columns (varchar(10), float, float, float)?
A procedure can't return a table as such. However you can select from a table in a procedure and direct it into a table (or table variable) like this:
create procedure p_x
as
begin
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t values('a', 1,1,1)
insert #t values('b', 2,2,2)
select * from #t
end
go
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t
exec p_x
select * from #t
I do this frequently using Table Types to ensure more consistency and simplify code. You can't technically return "a table", but you can return a result set and using INSERT INTO .. EXEC ... syntax, you can clearly call a PROC and store the results into a table type. In the following example I'm actually passing a table into a PROC along with another param I need to add logic, then I'm effectively "returning a table" and can then work with that as a table variable.
/****** Check if my table type and/or proc exists and drop them ******/
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'returnTableTypeData')
DROP PROCEDURE returnTableTypeData
GO
IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'myTableType')
DROP TYPE myTableType
GO
/****** Create the type that I'll pass into the proc and return from it ******/
CREATE TYPE [dbo].[myTableType] AS TABLE(
[someInt] [int] NULL,
[somenVarChar] [nvarchar](100) NULL
)
GO
CREATE PROC returnTableTypeData
#someInputInt INT,
#myInputTable myTableType READONLY --Must be readonly because
AS
BEGIN
--Return the subset of data consistent with the type
SELECT
*
FROM
#myInputTable
WHERE
someInt < #someInputInt
END
GO
DECLARE #myInputTableOrig myTableType
DECLARE #myUpdatedTable myTableType
INSERT INTO #myInputTableOrig ( someInt,somenVarChar )
VALUES ( 0, N'Value 0' ), ( 1, N'Value 1' ), ( 2, N'Value 2' )
INSERT INTO #myUpdatedTable EXEC returnTableTypeData #someInputInt=1, #myInputTable=#myInputTableOrig
SELECT * FROM #myUpdatedTable
DROP PROCEDURE returnTableTypeData
GO
DROP TYPE myTableType
GO
Consider creating a function which can return a table and be used in a query.
https://msdn.microsoft.com/en-us/library/ms186755.aspx
The main difference between a function and a procedure is that a function makes no changes to any table. It only returns a value.
In this example I'm creating a query to give me the counts of all the columns in a given table which aren't null or empty.
There are probably many ways to clean this up. But it illustrates a function well.
USE Northwind
CREATE FUNCTION usp_listFields(#schema VARCHAR(50), #table VARCHAR(50))
RETURNS #query TABLE (
FieldName VARCHAR(255)
)
BEGIN
INSERT #query
SELECT
'SELECT ''' + #table+'~'+RTRIM(COLUMN_NAME)+'~''+CONVERT(VARCHAR, COUNT(*)) '+
'FROM '+#schema+'.'+#table+' '+
' WHERE isnull("'+RTRIM(COLUMN_NAME)+'",'''')<>'''' UNION'
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #table and TABLE_SCHEMA = #schema
RETURN
END
Then executing the function with
SELECT * FROM usp_listFields('Employees')
produces a number of rows like:
SELECT 'Employees~EmployeeID~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("EmployeeID",'')<>'' UNION
SELECT 'Employees~LastName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("LastName",'')<>'' UNION
SELECT 'Employees~FirstName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("FirstName",'')<>'' UNION
You can use an out parameter instead of the return value if you want both a result set and a return value
CREATE PROCEDURE proc_name
#param int out
AS
BEGIN
SET #param = value
SELECT ... FROM [Table] WHERE Condition
END
GO
I had a similar situation and solved by using a temp table inside the procedure, with the same fields being returned by the original Stored Procedure:
CREATE PROCEDURE mynewstoredprocedure
AS
BEGIN
INSERT INTO temptable (field1, field2)
EXEC mystoredprocedure #param1, #param2
select field1, field2 from temptable
-- (mystoredprocedure returns field1, field2)
END
The Status Value being returned by a Stored Procedure can only be an INT datatype. You cannot return other datatypes in the RETURN statement.
From Lesson 2: Designing Stored Procedures:
Every stored procedure can return an integer value known as the
execution status value or return code.
If you still want a table returned from the SP, you'll either have to work the record set returned from a SELECT within the SP or tie into an OUTPUT variable that passes an XML datatype.
HTH,
John
Though this question is very old but as a new in Software Development I can't stop my self to share what I have learnt :D
Creation of Stored Procedure:
CREATE PROC usp_ValidateUSer
(
#UserName nVARCHAR(50),
#Password nVARCHAR(50)
)
AS
BEGIN
IF EXISTS(SELECT '#' FROM Users WHERE Username=#UserName AND Password=#Password)
BEGIN
SELECT u.UserId, u.Username, r.UserRole
FROM Users u
INNER JOIN UserRoles r
ON u.UserRoleId=r.UserRoleId
END
END
Execution of Stored Procedure:
(If you want to test the execution of Stored Procedure in SQL)
EXEC usp_ValidateUSer #UserName='admin', #Password='admin'
The Output:
create procedure PSaleCForms
as
begin
declare
#b varchar(9),
#c nvarchar(500),
#q nvarchar(max)
declare #T table(FY nvarchar(9),Qtr int,title nvarchar (max),invoicenumber nvarchar(max),invoicedate datetime,sp decimal 18,2),grandtotal decimal(18,2))
declare #data cursor
set #data= Cursor
forward_only static
for
select x.DBTitle,y.CurrentFinancialYear from [Accounts Manager].dbo.DBManager x inner join [Accounts Manager].dbo.Accounts y on y.DBID=x.DBID where x.cfy=1
open #data
fetch next from #data
into #c,#b
while ##FETCH_STATUS=0
begin
set #q=N'Select '''+#b+''' [fy], case cast(month(i.invoicedate)/3.1 as int) when 0 then 4 else cast(month(i.invoicedate)/3.1 as int) end [Qtr], l.title,i.invoicenumber,i.invoicedate,i.sp,i.grandtotal from ['+#c+'].dbo.invoicemain i inner join ['+#c+'].dbo.ledgermain l on l.ledgerid=i.ledgerid where (sp=0 or stocktype=''x'') and invoicetype=''DS'''
insert into #T exec [master].dbo.sp_executesql #q
fetch next from #data
into #c,#b
end
close #data
deallocate #data
select * from #T
return
end
Here's an example of a SP that both returns a table and a return value. I don't know if you need the return the "Return Value" and I have no idea about MATLAB and what it requires.
CREATE PROCEDURE test
AS
BEGIN
SELECT * FROM sys.databases
RETURN 27
END
--Use this to test
DECLARE #returnval int
EXEC #returnval = test
SELECT #returnval