Is there a SQL Server function type that doesn't return anything? - sql

I would like to create a SQL Server function that doesn't return anything but rather simply updates based on some input.
Looking at the documentation, there doesn't seem to be a function like this?
How can I acheive this behaviour?
Basically, I need a function type that I can exec at anytime to do some updating.
Like:
exec UpdateData 'derp'

A stored procedure, is a "type" of function, and it is usually used for situations just like yours, to modify some date when executed.
You can pass it parameters, 'derp', and create some SQL logic to update your records. In the end the stored procedure will just execute and won't return anything (actually, you can return information but it's not the topic of your question).

Create a stored procedure
e.g.
Create Procedure usp_UpdateDate
#Id int,
#Value varchar(100)
AS
Update TableName
Set Data= #Value
Where Id = #Id
Then you can
exec usp_UpdateDate 1,'value to update'

Related

Get first row, first column value from stored procedure

I am calling a stored procedure (that I can't modify) that returns a single value via a SELECT at the end of the procedure. I need to use that value in my own procedure. How can I get that value?
Here is an example of the procedure I am calling that I can not modify:
CREATE PROCEDURE [dbo].[SP_poorlywritten] (
....
)
BEGIN
....
SELECT #lastkey;
RETURN (0);
END
And here is what I am trying to do, but it doesn't work because this gets the return value, and what I need is that SELECT value:
exec #next_key = SP_poorlywritten 'tablename',1;
How can I store the first column, first row value from a store procedure?
If you cannot modify the existing stored procedure, you will not be able to utilize the RETURN as you would like to.
An alternative may be to insert the output of the procedure's select statement into a temp table, and then query that directly to populate a variable.
That would look like this.
CREATE TABLE #tmp
(
LastKey INT
)
INSERT INTO #tmp
EXEC [dbo].[SP_poorlywritten]
See this existing post for more details on how you might accomplish this.
As Aaron Bertrand pointed out, RETURN is for error/status. If you were able to modify the stored procedure, you would want to utilize an output parameter instead of RETURN. This is how you would do that.
CREATE PROCEDURE proc_name
#Output int OUTPUT
AS
<do some stuff>
SET #Output = <some_value>
GO
DECLARE #Output int
EXEC proc_name #Output = #Output

Specify stored procedure parameter with sql query

Let me preface by saying I'm not very knowledgeable about SQL and this made searching for an answer hard. I may be using the wrong 'wording.'
Given the following query to execute a stored procedure:
USE MyDB
SET NOCOUNT ON
EXECUTE dbo.adm_ExecuteProcedure
#installationID = 12345,
#monthOf = '03/01/2013'
GO
Can I use a select statement to dynamically look up 12345? The following does not work, but is what I am trying to do.
USE MyDB
SET NOCOUNT ON
EXECUTE dbo.adm_ExecuteProcedure
#installationID = (select id from installs where name = 'foo'),
#monthOf = '03/01/2013'
GO
I don't have permission to edit the stored procedure.
declare #id int;
select #id = id
from installs
where name = 'foo';
EXECUTE dbo.adm_ExecuteProcedure
#installationID = #id,
#monthOf = '03/01/2013';
Try storing it in a variable (syntax depends on your DB system)
What you can do is declare variable and select installationId in that variable from your select statement and then just use that variable while executing stored procedure. Did you got it.
well, you can do it, but in the code calling the stored procedure... or even in any query of the stored procedure, and in that case you wouldn't need the parameter at all...

Can I create a One-Time-Use Function in a Script or Stored Procedure?

In SQL Server 2005, is there a concept of a one-time-use, or local function declared inside of a SQL script or Stored Procedure? I'd like to abstract away some complexity in a script I'm writing, but it would require being able to declare a function.
Just curious.
You can create temp stored procedures like:
create procedure #mytemp as
begin
select getdate() into #mytemptable;
end
in an SQL script, but not functions. You could have the proc store it's result in a temp table though, then use that information later in the script ..
You can call CREATE Function near the beginning of your script and DROP Function near the end.
Common Table Expressions let you define what are essentially views that last only within the scope of your select, insert, update and delete statements. Depending on what you need to do they can be terribly useful.
I know I might get criticized for suggesting dynamic SQL, but sometimes it's a good solution. Just make sure you understand the security implications before you consider this.
DECLARE #add_a_b_func nvarchar(4000) = N'SELECT #c = #a + #b;';
DECLARE #add_a_b_parm nvarchar(500) = N'#a int, #b int, #c int OUTPUT';
DECLARE #result int;
EXEC sp_executesql #add_a_b_func, #add_a_b_parm, 2, 3, #c = #result OUTPUT;
PRINT CONVERT(varchar, #result); -- prints '5'
The below is what I have used i the past to accomplish the need for a Scalar UDF in MS SQL:
IF OBJECT_ID('tempdb..##fn_Divide') IS NOT NULL DROP PROCEDURE ##fn_Divide
GO
CREATE PROCEDURE ##fn_Divide (#Numerator Real, #Denominator Real) AS
BEGIN
SELECT Division =
CASE WHEN #Denominator != 0 AND #Denominator is NOT NULL AND #Numerator != 0 AND #Numerator is NOT NULL THEN
#Numerator / #Denominator
ELSE
0
END
RETURN
END
GO
Exec ##fn_Divide 6,4
This approach which uses a global variable for the PROCEDURE allows you to make use of the function not only in your scripts, but also in your Dynamic SQL needs.
In scripts you have more options and a better shot at rational decomposition. Look into SQLCMD mode (SSMS -> Query Menu -> SQLCMD mode), specifically the :setvar and :r commands.
Within a stored procedure your options are very limited. You can't create define a function directly with the body of a procedure. The best you can do is something like this, with dynamic SQL:
create proc DoStuff
as begin
declare #sql nvarchar(max)
/*
define function here, within a string
note the underscore prefix, a good convention for user-defined temporary objects
*/
set #sql = '
create function dbo._object_name_twopart (#object_id int)
returns nvarchar(517) as
begin
return
quotename(object_schema_name(#object_id))+N''.''+
quotename(object_name(#object_id))
end
'
/*
create the function by executing the string, with a conditional object drop upfront
*/
if object_id('dbo._object_name_twopart') is not null drop function _object_name_twopart
exec (#sql)
/*
use the function in a query
*/
select object_id, dbo._object_name_twopart(object_id)
from sys.objects
where type = 'U'
/*
clean up
*/
drop function _object_name_twopart
end
go
This approximates a global temporary function, if such a thing existed. It's still visible to other users. You could append the ##SPID of your connection to uniqueify the name, but that would then require the rest of the procedure to use dynamic SQL too.
Just another idea for anyone that's looking this up now. You could always create a permanent function in tempdb. That function would not be prefixed with ## or # to indicate it's a temporary object. It would persist "permanently" until it's dropped or the server is restarted and tempdb is rebuilt without it. The key is that it would eventually disappear once the server is restarted if your own garbage collection fails.
The scope of the function would be within TempDB but it could reference another database on the server with 3 part names. (dbname.schema.objectname) or better yet you can pass in all the parameters that the function needs to do its work so it doesn't need to look at other objects in other databases.

How to Suppress the SELECT Output of a Stored Procedure called from another Stored Procedure in SQL Server?

I'm not talking about doing a "SET NOCOUNT OFF". But I have a stored procedure which I use to insert some data into some tables. This procedure creates a xml response string, well let me give you an example:
CREATE PROCEDURE [dbo].[insertSomeData] (#myParam int) AS
DECLARE #reply varchar(2048)
... Do a bunch of inserts/updates...
SET #reply = '<xml><big /><outputs /></xml>'
SELECT #reply
GO
So I put together a script which uses this SP a bunch of times, and the xml "output" is getting to be too much (it's crashed my box once already).
Is there a way to suppress or redirect the output generated from this stored procedure? I don't think that modifying this stored procedure is an option.
thanks.
I guess i should clarify. This SP above is being called by a T-SQL Update script that i wrote, to be run through enterprise studio manager, etc.
And it's not the most elegant SQL i've ever written either (some psuedo-sql):
WHILE unprocessedRecordsLeft
BEGIN
SELECT top 1 record from updateTable where Processed = 0
EXEC insertSomeData #param = record_From_UpdateTable
END
So lets say the UpdateTable has some 50k records in it. That SP gets called 50k times, writing 50k xml strings to the output window. It didn't bring the sql server to a stop, just my client app (sql server management studio).
The answer you're looking for is found in a similar SO question by Josh Burke:
-- Assume this table matches the output of your procedure
DECLARE #tmpNewValue TABLE ([Id] int, [Name] varchar(50))
INSERT INTO #tmpNewValue
EXEC [ProcedureB]
-- SELECT [Id], [Name] FROM #tmpNewValue
I think I found a solution.
So what i can do now in my SQL script is something like this (sql-psuedo code):
create table #tmp(xmlReply varchar(2048))
while not_done
begin
select top 1 record from updateTable where processed = 0
insert into #tmp exec insertSomeData #param=record
end
drop table #tmp
Now if there was a even more efficient way to do this. Does SQL Server have something similar to /dev/null? A null table or something?
Answering the question, "How do I suppress stored procedure output?" really depends on what you are trying to accomplish. So I want to contribute what I encountered:
I needed to supress the stored procedure (USP) output because I just wanted the row count (##ROWCOUNT) from the output. What I did, and this may not work for everyone, is since my query was already going to be dynamic sql I added a parameter called #silentExecution to the USP in question. This is a bit parameter which I defaulted to zero (0).
Next if #silentExecution was set to one (1) I would insert the table contents into a temporary table, which is what would supress the output and then execute ##ROWCOUNT with no problem.
USP Example:
CREATE PROCEDURE usp_SilentExecutionProc
#silentExecution bit = 0
AS
BEGIN
SET NOCOUNT ON;
DECLARE #strSQL VARCHAR(MAX);
SET #strSQL = '';
SET #strSQL = 'SELECT TOP 10 * ';
IF #silentExecution = 1
SET #strSQL = #strSQL + 'INTO #tmpDevNull ';
SET #strSQL = #strSQL +
'FROM dbo.SomeTable ';
EXEC(#strSQL);
END
GO
Then you can execute the whole thing like so:
EXEC dbo.usp_SilentExecutionProc #silentExecution = 1;
SELECT ##ROWCOUNT;
The purpose behind doing it like this is if you need the USP to be able to return a result set in other uses or cases, but still utilize it for just the rows.
Just wanted to share my solution.
I have recently come across with a similar issue while writing a migration script and since the issue was resolved in a different way, I want to record it.
I have nearly killed my SSMS Client by running a simple while loop for 3000 times and calling a procedure.
DECLARE #counter INT
SET #counter = 10
WHILE #counter > 0
BEGIN
-- call a procedure which returns some resultset
SELECT #counter-- (simulating the effect of stored proc returning some resultset)
SET #counter = #counter - 1
END
The script result was executed using SSMS and default option on query window is set to show “Results to Grid”[Ctrl+d shortcut].
Easy Solution:
Try setting the results to file to avoid the grid to be built and painted on the SSMS client. [CTRL+SHIFT+F keyboard shortcut to set the query results to file].
This issue is related to : stackoverflow query
Man, this is seriously a case of a computer doing what you told it to do instead of what you wanted it to do.
If you don't want it to return results, then don't ask it to return results. Refactor that stored procedure into two:
CREATE PROCEDURE [dbo].[insertSomeData] (#myParam int) AS
BEGIN
DECLARE #reply varchar(2048)
--... Do a bunch of inserts/updates...
EXEC SelectOutput
END
GO
CREATE PROCEDURE SelectOutput AS
BEGIN
SET #reply = '<xml><big /><outputs /></xml>'
SELECT #reply
END
From which client are you calling the stored procedure? Say it was from C#, and you're calling it like:
var com = myConnection.CreateCommand();
com.CommandText = "exec insertSomeData 1";
var read = com.ExecuteReader();
This will not yet retrieve the result from the server; you have to call Read() for that:
read.Read();
var myBigString = read[0].ToString();
So if you don't call Read, the XML won't leave the Sql Server. You can even call the procedure with ExecuteNonQuery:
var com = myConnection.CreateCommand();
com.CommandText = "exec insertSomeData 1";
com.ExecuteNonQuery();
Here the client won't even ask for the result of the select.
You could create a SQL CLR stored procedure that execs this. Should be pretty easy.
I don't know if SQL Server has an option to suppress output (I don't think it does), but the SQL Query Analyzer has an option (under results tab) to "Discard Results".
Are you running this through isql?
You said your server is crashing. What is crashing the application that consumes the output of this SQL or SQL Server itself (assuming SQL Server).
If you are using .Net Framework application to call the stored procedure then take a look at SQLCommand.ExecuteNonQuery. This just executes stored procedure with no results returned. If problem is at SQL Server level then you are going to have to do something different (i.e. change the stored procedure).
You can include in the SP a parameter to indicate if you want it to do the select or not, but of course, you need to have access and reprogram the SP.
CREATE PROCEDURE [dbo].[insertSomeData] (#myParam int, #doSelect bit=1) AS
DECLARE #reply varchar(2048)
... Do a bunch of inserts/updates...
SET #reply = '<xml><big /><outputs /></xml>'
if #doSelect = 1
SELECT #reply
GO
ever tried SET NOCOUNT ON; as an option?

What is the best way to assign the returned value of a stored proc to a variable in SQL?

I have a stored procedure that returns a valueI call it from other stored procedures that need to retrieve this value. The calling stored procedure is inside a transaction, the stored procedure that returns the value (and actually creates the value and stores it in a table that no other proc touches) is not inside its own transaction, but would be part of the caller's transaction.
The question is this, what is the most efficient way of retrieving the return value of the stored procedure and storing it in a variable in the calling proc?
Currently I have the following and I'm wondering if its very inefficient?
DECLARE #tmpNewValue TABLE (newvalue int)
INSERT INTO #tmpNewValue EXEC GetMyValue
DECLARE #localVariable int
SET #localVariable = (SELECT TOP 1 newvalue FROM #tmpNewValue )
Isn't there a more straight forward way of doing this? Isn't this an expensive (in terms of performance) way?
My stored proc doesn't have an output param, it just returns a value. Would using an output param be faster?
For what it's worth I'm using MS SQL Server 2005
If your getting a single return variable then yes this is innefficent you can do:
declare #localVariable int
exec #localVariable =GetMyValue
select #localVariable
See How to Share Data Between Stored Procedures
By some reasons 'exec #localVariable =GetMyValue' is not working for me (MS SQL 2005), it's always return 0 value (They have the same issue).
My opinion is:
if you can change stored procedure, add output parameter.
else if you can remove procedure, rewrite it as a function.
else use table variable, as you do.
Is this proc returning a rowset of 1 row and 1 column or no rowset at all and you just want to capture the returncode?
If you want just the returncode then use Josh's method otherwise use a OUTPUT parameter sicne it will be much faster than what you are doing now
To Explain what I mean run this code
use tempdb
go
create proc GetMyValue
as
select 1
go
create table #temp (id int)
declare #localVariable int
insert #temp
exec #localVariable =GetMyValue
select #localVariable,* from #temp
Try this:
create proc AvilableSeats
as
declare #v1 int,#v2 int
exec #v1= determinPath_Capacity 1,'Sat-Tue',32
exec #v2=Student_fGroup '6/12/2009'
select #v1-#v2