Can we call a stored procedure from a function in SQL? What's the reason?
Yes.
You can do this with a bit of a hack involving openrowset but it's not recommended as it will open a new connection.
CREATE FUNCTION dbo.test ()
RETURNS varchar(200)
AS
BEGIN
RETURN (Select top 1 [Name] from
OPENROWSET('SQLNCLI','Server=.\SQL2008;Trusted_Connection=yes;','SET NOCOUNT ON;SET FMTONLY OFF;EXEC MASTER..SP_HELP')
)
END
GO
SELECT dbo.test()
Functions can only read data, they can't update or change anything. It follows that functions are not allowed to call stored procedures.
Quick answer: No.
Why: A stored procedure does not produce any output that can be re-used inside SQL.
To be efficient a function should be deterministic, i.e. the output should only be depending on the input, so that the result can be cached.
If you want to call a stored procedure from a function, yout have to specifically make the function non-deterministic.
Related
Hey guys I want to use SQL Server function,
I never use function in SQL Server and I only know that function must return a value so I have two stored procedure (1 for insert and 1 for select)
My stored procedures look like this
For insert:
create proc INS_tblteststud
#stdtid int=null,
#name varchar(50) =null,
#fullname varchar(50)=null,
#address varchar(50)=null,
#city varchar(50)=null,
#country varchar(50)=null,
#contno varchar(50)=null
as
begin
insert into tbl_student_test(name,fullname,address,city,country,contno)
values
(#name,#fullname,#address,#city,#country,#contno)
end
And for select:
Create proc SEL_tblteststud
as
begin
select * from tbl_student_test
end
Now I want to know, how can I convert these statements(Insert, Select) into functions? And which is better to use stored procedure or function?
You are mixing procedure and function...
A procedure is meant for doing something
A function is meant for reading only
It is not allowed to place data changing commands within a function.
What you are trying is just not possible...
UPDATE Some insight about functions and procedures
There are three types of functions
scalar functions: Return one scalar value and are very bad performing
multi statement table valued functions (with BEGIN ... END): Return a resultset, but are bad performing too
inline table valued functions: They are great, but restricted. Think of them like of a VIEW with pre-compiled parameters
A procedure has a return value too, which is of tpye INT and is not used to return the SP's result, but kind of execution status.
A SP might just do something and return no procedure result at all. If you want to return procedural results you must either use
output parameters
or you must call a SELECT within your SP. It is possible to grab the result of an internal SELECT from outside, but this is very cumbersome...
There are several limitations between a SQL Server stored procedure and a user defined function.
UDF's Can't
use nondeterministic functions
change the state of the database
Return messages to the caller
have any side effects
A stored procedure can return multiple record sets and they are not required to return the same fields each time.
create proc custom.sproc_CrazyFields
#ThisItem int
as
begin
if #ThisItem < 10
begin
select 'this' as ThisField, 'that' as ThatField, 'theOther' as theOtherField;
end
else
begin
Select 'theOther' as theOtherField, 'that' as thatField, 'this' as thisField;
end
end
go
exec custom.sproc_CrazyFields 4
exec custom.sproc_CrazyFields 40
An inline function is only going to return a single select statement.
A multistatement function has to declare the returned table.
Is there a way to dynamically return a result with changing columns with a UDF or is this one of the differences?
Sorry, you can't use dynamic SQL in a function. Maybe what you can do is write a stored procedure that creates a function in dynamic SQL, calls the function, then drops it. But then why not just build the query inline at that point.
I would like to call a stored procedure or user-defined function that returns a dynamic table that is created via a pivot expression. I don't know the number of columns up front.
Is this possible? (I am not interested in temporary tables)
You can do that via stored procedure as it can return any kind of table, question is what are you trying to achieve and what will you do with data that you have no idea about?
This cannot be done with functions (as the returned table structure must be pre-defined), but it can be done with a stored proceed. Some psuedo-code:
CREATE PROCEDURE Foo
As
DECLARE #Command
SET #Command = 'SELECT * from MyTable'
-- For debugging, work in an optional PRINT #Command statement
EXECUTE (#Command)
RETURN 0
When you run stored procedure Foo, it builds your query as a string in #Command, and then dynamically executes it without knowing anything about what is being queried or returned, and the data set returned by that EXECUTE statement is "passed back" to the process that called the procedures.
Build your query with care, this stuff can be really hard to debug. Depending on your implementation, it might be a source of SQL injection attacks (remember, the stored procedure really doesn't know what that dynamic query is going to do). For quick stuff, EXECUTE() works fine, but for safer and more useful (if elaborate) solutions, look into sp_ExecuteSQL.
Yes, you can do this from a Stored Procedure, but not from a user-defined Function. It is worth looking into the Table Value Function, I believe you can also return a dynamic table from there, but I have not used that myself.
Assume I have some stored procedure (and I can't change it) which is returning a result set:
create procedure test_procedure
as
begin
select 1
end
I know that I can insert result set into table, so it would be hidden to the calling code:
declare #t table(i int)
insert into #t
exec test_procedure
Are there any other ways to hide returning result set from the calling code?
Updated
It looks like I've been a bit confusing. I'm looking only for T-SQL answers (not .NET ones).
No, there is no other solution. However, you should refactor your procedure to do only what you need. If you need the output for other calls, try to split the procedure into two.
Use optional Output Parameter.
or use below case
Create procedure Check #c int
as
begin
if #c = 1
select 1
else
print 1
end
write any condition that will satisfy and that returns you specified values.
use that parameter as optional so no other change in your procedure will come.
Would you rather try to return your data through an output parameter, and return a status code as the procedure's return value?
You couldn't easily return a full resultset through that output parameter, but you could return some delimited data in a format of your choosing.
I have a Stored Procedure that rolls-back a series of operations. I want to call this from within another SP.
The problem is that the inner SP returns a record set with a single value that indicates the degree of success.
This approach worked well and has some advantages in our context, but in retrospect, I would have done it the conventional way with a Return value or an Output parameter.
I could always change this SP to use this approach and modify the calling code, but a) I don't want to dabble with any more code than I have to, and b) at an intellectual level, I'm curious to see what alternative solution there may be, if any.
How (if at all) can I call this SP and determine the value of the singleton recordset returned?
Thanks
A stored procedure returns a record set like any other, so you can actually do this:
INSERT INTO MyTable (
MyValue
)
EXEC dbo.MyStoredProcedure
The EXEC takes the place of a SELECT statement. To get the value, just SELECT from the table you inserted into. Typically, this would be a temp table.
The other option is to convert the stored procedure that returns a recordset into a function that returns a table.
Ant's approach is probably best if you want to minimize the changes to your system.
Normally you would use a temporary table for that approach since you can't use an exec statement to insert into a table variable.
Here's a variation which will work well if you need to use this for MULTIPLE recordsets.
CREATE TABLE #outsidetable (...)
exec spInsideProcedure
SELECT * FROM #outsidetable
inside spInsideProcedure
INSERT INTO #outsidetable SELECT <blah blah blah>
I tried Ant's approach and it worked a treat:
Declare #Success tinyint
Declare #Response Table (Success int)
Insert into #Response(Success)
Exec Fix_RollbackReturn 12345, 15
Select #Success=Success from #Response
As you can see I used a Table Variable rather than a temporary table because slightly more efficient than a temporary table.
Thanks for all your help guys.
EDIT: It appears that Dave was right after all. That is, my Exec-into-Table-variable approach worked on my SQL2005 development machine, but when moved to the Live (SQL2000) machine it objected, so I had to change to the temporary table approach.
It's a little annoying, especially since in a couple of weeks we are upgrading to SQL2005 across the board(!).