I have a stored procedure sp_1 that calls another stored procedure sp_1_1.
I know how to suppress the results from sp_1_1 using this trick.
The real problem is that sp_1_1 itself also call another stored procedure sp_1_1_1 which ALSO returns it's results to sp_1_1!!
I may not change either sp_1_1 or sp_1_1_1, and can only change sp_1.
The results returned to sp_1 are 2 recordsets, with the first from sp_1_1 and the second from sp_1_1_1.
SUMMARY:
sp_1 (Needs to suppress two recordsets returned from below)
+---- sp_1_1 (returns its own results, then results from below)
+----------sp_1_1_1 (returns results)
Firstly, an aside, SQL Server "Denali" gives you new options for handling resultsets.
In this case, because you're nesting you obviously can't use the insert/exec trick.
One kludgy workaround, if you don't want to refactor too much, is to add a parameter to the proc with a default, something like #SuppressResults bit = false.
Then, in the routines that need to be nested, call it explicitly with #SuppressResult=True, and then alter the code in the routines to not select results if #SuppressResults=True.
The important thing is to provide a default and put the parameter at the end. That will prevent existing calls to the routine from elsewhere in the code base needing to be altered.
Related
When I execute one of my stored procedures manually, I have to populate several variables.
Most of the variables don't change each time it is run; is it possible to pre-populate the "Value" box so that it only needs to be changed when necessary?
I am reluctant to hard code in the script as there was a series of interlinked procedures which I need to keep dynamic
I'm going to go out on a limb here and guess that you're talking about SQL Server, and that you're executing your procedure through SSMS, because of your description of the graphical interface. In the future, please tag your question with the specific database platform that the question pertains to, and try to be responsive to early comments. You'll get answers much, much faster. (If I'm wrong, just undo the tagging I added to your question.)
Although stored procedures can contain variables, what you're talking about here are parameters; values that are passed into the procedure from the calling code or application.
Parameters can be defined with default values in their declarations.
CREATE OR ALTER PROCEDURE dbo.SomeProc (
#SomeBigIntegerValue bigint = 42
)
AS...
When default values exist, the parameter becomes optional for the caller. The procedure can now be called with or without explicit parameters. Either of these will run.
EXECUTE dbo.SomeProc;
EXECUTE dbo.SomeProc
#SomeBigIntegerValue = 37;
In the first instance, the procedure will use the default value, 42. In the second instance, it will use the parameter value, 37.
You'll note that I named the parameter in the call. That's a best practice, generally, to avoid confusion, but it also allows you to send the parameters in any order. If you don't name them, they will be interpreted in the order they're declared, so you run all manner of risks there.
If you choose to execute the procedure through the GUI, the default values won't be pre-populated, but you can see which parameters have defaults and which don't by expanding the Parameters tab under the procedure name in SSMS. I couldn't find an example with defaults, but it'll looks something like this:
If you want the procedure to use the default value, just tick the Pass Null Value check box.
(In case you're wondering, we have a truncate proc so that our ETL service accounts can have scaled back permissions without having to do fully-logged, row-by-row deletions...)
I'm writing a stored procedure which checks for the existence of various tables in various databases, as well as the permissions that the user executing the stored procedure has on those tables. The stored procedure itself resides within a user database (i.e. it's not in the Master db).
To perform my checks, my stored procedure contains lots of SELECT statements. Each of those obviously returns a record set. What I would like is to somehow suppress these record sets so that they are not returned by the stored procedure, and instead return my own, single record set which is just a collection of messages relating to each check the stored procedure performs.
I think the obvious answer is to use a table-valued function instead, but I've not been able to recreate my tests successfully in a Function as they appear in the stored procedure. For starters, I'm having to use temporary tables (not possible in a function) and dynamic SQL (not very compatible with table parameters).
I think I've basically got two choices:
Rewrite my stored procedure as a function and figure out how to do the checks a different way.
Continue using my stored procedure and use an OUTPUT parameter to return my result messages, probably as a delimited string, and in the associated ASP.NET application just ignore all the record sets the stored procedure returns .
Neither of these solutions is very satisfactory. Before I spend any more time pursuing either one, is there a way to discard the record sets produced by the SELECT statements in a stored procedure and explicitly define what record I want it to return?
Hmm, I only can speculate here...
Are you using something like
SELECT ...;
IF ##rowcount > 0
BEGIN
...
END;
?
Then you can rewrite it using something like
IF EXISTS (SELECT ...)
BEGIN
...
END;
or
DECLARE #variable integer;
SELECT #variable = count(*) ...;
IF #variable > 0
BEGIN
...
END;
In general point the results of your queries to a target (variable, table, expression, ...), then they don't get outputted.
And then just execute the query for your desired result in the end.
In my opinion, here is almost no reason to have stored procedures produce record sets. That is what stored functions are for. On occasion, it is needed, because of the use of dynamic SQL or other stored procedures, but not as a general practice. Much, much too often, I see stored procedures being used where stored functions or views are more appropriate.
What should you do? Even SELECT statement in the stored procedure should be one of the following:
Setting (local) variables.
Saving the results in a temporary table or table variable.
The logic for the stored procedure should be working on the local variables. The results should be returned using OUTPUT parameters.
If you need to return rows in a tabular format, you can do that using tables explicitly (such as a global temporary table or real table). Or, you can have one SELECT at the end that does return a single result set. However, if you need this and can phrase the stored procedure as a function, that is better in my opinion.
Is it possible (using only T-SQL no C# code) to write a stored procedure to execute a series of other stored procedures without passing them any parameters?
What I mean is that, for example, when I want to update a row in a table and that table has a lot of columns which are all required, I want to run the first stored procedure to check if the ID exists or not, if yes then I want to call the update stored procedure, pass the ID but (using the window that SQL Server manager shows after executing each stored procedure) get the rest of the values from the user.
When I'm using the EXEC command, I need to pass all the parameters, but is there any other way to call the stored procedure without passing those parameter? (easy to do in C# or VB, I mean just using SQL syntax)
I think you are asking "can you prompt for user input in a sql script?". No not really.
You could actually do it with seriously hack-laden calls to the Windows API. And it would almost certainly have serious security problems.
But just don't do this. Write a program in C#, VB, Access, Powerscript, Python or whatever makes you happy. Use an tool appropriate to the task.
-- ADDED
Just so you know how ugly this would be. Imagine using the Flash component as an ActiveX object and using Flash to collect input from the user -- now you are talking about the kind of hacking it would be. Writing CLR procs, etc. would be just as big of a hack.
You should be cringing right now. But it gets worse, if the TSQL is running on the sql server, it would likely prompt or crash on the the server console instead of running on your workstation. You should definitely be cringing buy now.
If you are coming from Oracle Accept, the equivalent in just not available in TSQL -- nor should it be, and may it never be.
Right after reading your comment now I can understand what you are trying to do. You want to make a call to procedure and then ask End User to pass values for Parameters.
This is a very very badddddddddddddddddddd approach, specially since you have mentioned you will be making changes to database with this SP.
You should get all the values from your End Users before you make a call to your database(execute procedure), Only then make a call to database you Open a transaction and Commit it or RollBack as soon as possible and get out of there. as it will be holding locks on your resources.
Imagine you make a call to database (execute sp) , sp goes ahead and opens a transaction and now wait for End user to pass values, and your end user decides to go away for a cig, this will leave your resources locked and you will have to go in and kill the process yourself in order to let other user to go and use database/rows.
Solution
At application level (C#,VB) get all the values from End users and only when you have all the required information, only then pass these values to sp , execute it and get out of there asap.
You can specify the parameters by prefixing the name of the parameter with the # sign. For example, you can call an SP like this:
EXEC MyProc #Param1='This is a test'
But, if you are asking if you can get away with NOT providing required parameters, the answer is NO. Required is required. You can make them optional by providing a default value in the declaration of the SP. Then you can either not pass the value or call it like this:
EXEC MyProc #Param1=DEFAULT
--OR
EXEC MyProc DEFAULT
With a stored procedure in a database, would the following situation be true?
I have a procedure that queries a very large table, and in my query I call the stored procedure, and follow it with a WHERE record_class = "THE ONE IM LOOKING FOR".
In the stored procedure I'm not limiting the records by the record_class, so does the WHERE clause do anything other than filter the results that the procedure returns?
In other words, if I wanted to speed up the results because it takes too long, would adding a parameter for the record_class to the procedure and selecting only those when it performs its tasks be quicker than using the WHERE clause?
Your analysis is completely true, if you apply the condition directly in your stored procedure instead of outside it will for sure be more performant.
In the first situation, your procedure will return every rows without applying your condition (this condition is completely unknown for the procedure) and this result will then be filtered with your WHERE clause.
Depending on your needs, the best solution may be to define a parameter for your stored procedure so you can pass this parameter at execution and the result will be filtered. I don't know exactly what is the purpose of your procedure but by doing so, you'll keep the possibility to execute the same procedure for multiple situations (you simply need to pass the record_class you want to filter the result or let it NULL if you want the entire data).
This approach requires a little modification to your procedure (adding a parameter) and a modification of your query (adding the WHERE clause that filters the result if needed).
Hope this will help you.
There is a function having a parameter. The function internally invokes a stored procedure with the parameter. And clients can pass a string to the function through HTTP requests.
I'm trying to add a method to remove any possibilities of injecting dangerous SQL statement through the parameter. The method name is IsSQLParameterSafe() and it returns boolean values depending on the parameter. If the value is safe to execute, then the method will return true, otherwise it returns false.
In my case, the parameter doesn't have to have blanks so if there are any whitespaces, then it'll return false. Also, I'm going to limit the length of the input up to 64 because its the maximum length of the parameter.
Do you think that my idea will work? If not, can you suggest ideas?
Thanks
You can use a parameterized query even with stored procedures. This is the best way to deal with SQL injection risks. It's difficult to be more specific without knowing what language you're using, but in Java, for example, you'd use something similar to this:
String callStmt = "CALL PROC(?)";
PreparedStatement prepStmt = con.prepareStatement(callStmt);
prepStmt.setString(1, parameter);
ResultSet rs = prepStmt.executeQuery();
You might also be interested in the OWASP SQL Injection Prevention Cheat Sheet, which goes into more detail.
You won't need to worry, unless you are stitching the SQL together manually and then executing it with the EXEC command.
For example, this is a simple Stored Procedure:
CREATE PROCEDURE DeleteRecord
(
#name VARCHAR(64)
)
AS
BEGIN
DELETE FROM Records WHERE [Name] = #name
END
If you attempt to pass this string into the procedure...
name OR 1=1
...then the Procedure will Delete 0 records, because no one has this exact name.
Why doesn't it delete everything?
The Stored Procedure doesn't stitch the SQL together into a big string (you often see this sort of thing in tutorials for beginners in PHP). Instead, it passes the original SQL statement, then each parameter as a distinct argument. I don't know the technical details of how this works, but I know from experience that adding slashes and quotes and garbled characters will not break this query.
But...
If you are writing Dynamic SQL, and if you parameter represents a Table or Column name, then you need to be more careful. I would use a white list for that.
http://www.sommarskog.se/dynamic_sql.html