Is it possible to EXEC a T-SQL stored procedure that has an ouput parameter while ignoring SELECT statement? - tsql

I am calling one stored procedure from another, and the procedure I am calling has an output parameter. I am then piping the output value into a local variable. That's all well and good, but the problem is that this procedure also has a select statement in it, so when I exec, the results of the procedure are being returned in the final results set.
Is there a way to simply get the value of the output parameter, and ignore everything else?

While technically yes, you shouldn't do it. The engine consumes resources to produce the result set you ignore. You may also produce unnecessary contention. If you don't need the result set, you need another procedure that should only produce the output you desire.

I'm sure there are some tricks for doing this - but the obvious solution that springs to mind is:
INSERT INTO #my_rubbish_temp_table_that_i_CREATEd_earlier
EXEC dbo.mySproc #a, #b, #c OUTPUT
...as per Remus' response, this is a waste of CPU, I/O, etc.
If you can add an additional parameter to your stored procedure that allows the suppression of the resultset, that'd be grand.

Related

Perl DBI: Insert a whole hash in a single call, complement to fetchall_hashref()

I am using Perl DBI with DBD::Informix but I suspect the exact database is not important to this question. Bottom line: I'm looking for a mass-insert method where I can insert the contents of a hash [of hashes] into a table in one call.
Commentary:
I have grown enamored of the Perl DBI method fetchall_hashref(), wherein I can run the query and fetch the whole blessed active set - which may be thousands of rows - into a hash in one call.
I'm reading through the POD on both of these modules, looking for some equivalent of this in an insert statement or PUT call, something like a putall_hashref() method. The best I find is a simple one-row insert, where I've PREPAREd an INSERT statement with ? placeholders and then execute the PREPAREd stament. I've used a PUT cursor available in ESQL/C (and Informix-4GL) but even those are still one row at time.
I need a mass-insert method.
Is such a method in there someplace but I've missed it?
I see the comments by Shawn and zdim.
Shawn & zdim,
Example of current (untested) code, though I've used similar stuff before:
$db_partns = $extract_smi_p->fetchall_hashref("partition");
# Pulls from temp tab in DB1
...
Now loop to insert each row from above hash into new temp table in another DB
for my $partn (keys %$db_partns)
{
$put_statement_p->execute(#{$db_partns->{$partn}}{#partn_fields});
}
Note: #partn_fields is an array of keys i.e. column names. (Using hash-slice scheme.)
To use execute_array() I'd need to separate all values in each column into a separate array. Thanks for the clever idea; I may use it some day. But to set that up is an even uglier setup than I'm already doing.

PHP and sanitizing strings for use in dynamicly created DB2 queries

I'm relatively new to DB2 for IBMi and am wondering the methods of how to properly cleanse data for a dynamically generated query in PHP.
For example if writing a PHP class which handles all database interactions one would have to pass table names and such, some of which cannot be passed in using db2_bind_param(). Does db2_prepare() cleanse the structured query on its own? Or is it possible a malformed query can be "executed" within a db2_prepare() call? I know there is db2_execute() but the db is doing something in db2_prepare() and I'm not sure what (just syntax validation?).
I know if the passed values are in no way effected by the result of user input there shouldn't be much of an issue, but if one wanted to cleanse data before using it in a query (without using db2_prepare()/db2_execute()) what is the checklist for db2? The only thing I can find is to escape single quotes by prefixing them with another single quote. Is that really all there is to watch out for?
There is no magic "cleansing" happening when you call db2_prepare() -- it will simply attempt to compile the string you pass as a single SQL statement. If it is not a valid DB2 SQL statement, the error will be returned. Same with db2_exec(), only it will do in one call what db2_prepare() and db2_execute() do separately.
EDIT (to address further questions from the OP).
Execution of every SQL statement has three stages:
Compilation (or preparation), when the statement is parsed, syntactically and semantically analyzed, the user's privileges are determined, and the statement execution plan is created.
Parameter binding -- an optional step that is only necessary when the statement contains parameter markers. At this stage each parameter data type is verified to match what the statement text expects based on the preparation.
Execution proper, when the query plan generated at step 1 is performed by the database engine, optionally using the parameter (variable) values provided at step 2. The statement results, if any, are then returned to the client.
db2_prepare(), db2_bind_param(), and db2_execute() correspond to steps 1, 2 and 3 respectively. db2_exec() combines steps 1 and 3, skipping step 2 and assuming the absence of parameter markers.
Now, speaking about parameter safety, the binding step ensures that the supplied parameter values correspond to the expected data type constraints. For example, in the query containing something like ...WHERE MyIntCol = ?, if I attempt to bind a character value to that parameter it will generate an error.
If instead I were to use db2_exec() and compose a statement like so:
$stmt = "SELECT * FROM MyTab WHERE MyIntCol=" . $parm
I could easily pass something like "0 or 1=1" as the value of $parm, which would produce a perfectly valid SQL statement that only then will be successfully parsed, prepared and executed by db2_exec().

TSQL: execute procedure with a parameter that can have two values

Hello all,
I want to execute the following procedure:
EXECUTE MYDB.dbo.MYPROCEDURE
#gender='male',
#status='single'
The status can be single, divorced or married.
I need to execute the procedure having all the males that are single and divorced.
Ho can I do that?
Thanks a lot
The best way to do this would be to change your stored procedure over to a table-value function. Then you could call it twice and UNION ALL the results to get one resultset. The other way to do it would be to just call the stored procedure twice and add the results together yourself.
Unless you are fine with getting two resultsets back (by executing the statement twice), you will need to make some sort of modification to your SQL statement.
That's just not possible unless you rewrite the procedure
This is not possible without changing the Procedure.
One option would be to set the value as singledivorced and have the following WHERE clause:
WHERE [status]=#status
OR (#status='singledivorced' AND ([status]='single' or [status]='divorced'))

Execute statements for every record in a table

I have a temporary table (or, say, a function which returns a table of values).
I want to execute some statements for each record in the table.
Can this be done without using cursors?
I'm not opposed to cursors, but would like a more elegant syntax\way of doing it.
Something like this randomly made-up syntax:
for (select A,B from #temp) exec DoSomething A,B
I'm using Sql Server 2005.
I dont think what you want to to is that easy.
What i have found is that you can create a scalar function taking the arguments A and B and then from within the function execute an Extended Stored Procedure. This might achieve what you want to do, but it seems that this might make the code even more complex.
I think for readibility and maintainability, you should stick to the CURSOR implementation.
I would look into changing the stored proc so that it can work against a set of data rather than a single row input.
Would CROSS/OUTER APPLY do what you want if you need RBAR processing.
It's elegant, but depends on what processing you need to do

What is the best way to return an error from a TSQL Proc?

Here’s the scenario:
You load a page, which renders based on the data in the database (call these the “assumptions”)
Someone changes the assumptions
You submit your page
ERROR!
The general pattern to solve this problem is this (right?):
In your save proc, inside a begin and commit transaction, you validate your assumptions first. If any of them changed, you should return a graceful error message, something like an XML list of the ID’s you had problems with, that you handle in the page rather than let it be handled by the default error handling infrastructure.
So my question is what is the best way to do that?
Return the xml list and an error flag in out parameters that are unset and 0 if it completes correctly?
Use an out parameter to return an error status, and the result of the proc be either the error list or the valid results of the proc?
Something else? (I should note that raiseerror would cause the proc to be in error, and get picked up by the default error handling code)
Update: I would like to return a maniplatable list of IDs that failed (I plan to highlight those cells in the application). I could return them in CSV format in RAISEERROR, but that seems dirty.
I agree - I like RAISEERROR:
-- Validate #whatever
IF #whatever >= '5'
BEGIN
RAISERROR ('Invalid value for #whatever - expected a value less than 5, but received %s.', 10, 1, #whatever)
RETURN 50000
END;
Use the RAISERROR function with the appropriate severity and/or wait level. If you use a low severity this does not necessarily cause an exception, as you contend, and with .Net at least its pretty simple to retrieve these messages. The only downside is that with the StoredProcedure command type in .Net messages are only pumped in groups of 50.
Stored procedures can return multiple result sets. Based on your update, you could also insert errored ids into a temporary table, and then at the end of your procedure select the records from that table as an additional result set you can look at.
I would do an output parameter with a message, the return will already have something which is not 0 if there is an error
also be careful with doomed transaction and check with xact_error, see Use XACT_ABORT to roll back non trapable error transactions