Passing multiple parameters to a SQL Server stored procedure - sql-server

I'm using SQL Server 2012, and I have a stored procedure with more than 25 parameters, which I need to call from C#. In my experience, having this many parameters can cause headaches when things go wrong, trying to identify which parameter is wrong/missing/whatever.
I've used Oracle in the past, which has the concept of user Defined Types, so it is possible to create a Type, which contains the 25 parameters, and pass this in instead. Now we have just one parameter.
What's the equivalent of this in SQL Server? I've read about Table Value parameters, and it seems obvious that this is what I should use, but I'm wondering if this is overkill for what would only ever have one row (i.e. one set of parameters). Every example I've seen describes how to use these to pass in multiple rows, so I'm wondering if there's a simpler way that I've missed.

Related

Can I make TADOStoredProc apply given parameters to the target procedure by name?

I am trying to call a stored procedure from delphi7. The procedure also contains parameters with default values. As far as I understand I can call this procedure without explicitly passing values for parameters, having defaults. That's what I did in my delpho code.
But..
The result of appeared to be confusing. The parameter I skipped did get some value. That was the value for the next parameter. And it appeared the last parameter that didn't get its value instead in the end.
I tried to search and found this article. So, it turns out to be, that delphi ignored the names I gave to the parameteres of the TADOStoredProc and just passed them in the order I added them to the parameters' collection, i.e. the last parameter (happily it was also optional and no exception was thrown) wasn't passed to the procedure.
I see the answer by #crefird, suggesting to use TADOQuery instead of TADOStoredProc. But I don't like the approach. I'd better give certain values to all the parameters and don't use the optional parameters feature at all.
So, is there a better solution to make delphi specify parameters to a stored procedure by their names, when using TADOStoredProc?
You could make a TADOStoredProc at design time and have it populate its parameters collection. If you don't have a form to put it on you could use a DataModule.
Years ago I learnt the same lesson as you - the parameter names are ignored. Maintaining and growing the codebase that uses Delphi & SQL Server over the past ten years has been made easier by putting any new SP parameters at the END of the parameter list and, if desired, making them optional.
I have seem people make the TADOStoredProc object and then call its refreshParams (or refreshParameters - not sure of the name) method. That would involve a whole extra trip to the database which is probably to be avoided.

Define a String constant in SQL Server?

Is it possible in SQL Server to define a String constant? I am rewriting some queries to use stored procedures and each has the same long string as part of an IN statement [a], [b], [c] etc.
It isn't expected to change, but could at some point in future. It is also a very long string (a few hundred characters) so if there is a way to define a global constant for this that would be much easier to work with.
If this is possible I would also be interested to know if it works in this scenario. I had tried to pass this String as a parameter, so I could control it from a single point within my application but the Stored Procedure didn't like it.
You can create a table with a single column and row and disallow writes on it.
Use that as you global string constant (or additional constants, if you wish).
You are asking for one thing (a string constant in MS SQL), but appear to maybe need something else. The reason I say this is because you have given a few hints at your ultimate objective, which appears to be using the same IN clause in multiple stored procedures.
The biggest clue is in the last sentence:
I had tried to pass this String as a
parameter, so I could control it from
a single point within my application
but the Stored Procedure didn't like
it.
Without details of your SQL scripts, I am going to attempt to use some psychic debugging techniques to see if I can get you to what I believe is your actual goal, and not necessarily your stated goal.
Given your Stored Procedure "didn't like that" when you tried to pass in a string as a parameter, I am guessing the composition of the string was simply a delimited list of values, something like "10293, 105968, 501940" or "Juice, Milk, Donuts" (pay no attention to the actual list values - the important part is the delimited list itself). And your SQL may have looked something like this (again, ignore the specific names and focus on the general concept):
SELECT Column1, Column2, Column3
FROM UnknownTable
WHERE Column1 IN (#parameterString);
If this approximately describes the path you tried to take, then you will need to reconsider your approach. Using a regular T-SQL statement, you will not be able to pass a string of parameter values to an IN clause - it just doesn't know what to do with them.
There are alternatives, however:
Dynamic SQL - you can build up the
whole SQL statement, parameters and
all, then execute that in the SQL
database. This probably is not what
you are trying to achieve, since you
are moving script to stored
procedures. But it is listed here
for completeness.
Table of values -
you can create a single-column table
that holds the specific values you
are interested in. Then your Stored
Procedure can simply use the column
from this table for the IN clause).
This way, there is no Dynamic SQL
required. Since you indicate that
the values are not likely to change,
you may just need to populate the
table once, and use it wherever
appropriate.
String Parsing to
derive the list of values - You can
pass the list of values as a string,
then implement code to parse the
list into a table structure on the
fly. An alternative form of this
technique is to pass an XML
structure containing the values, and
use MS SQL Server's XML
functionality to derive the table.
Define a table-value function that
returns the values to use - I have
not tried this one, so I may be
missing something, but you should be
able to define the values in a
table-value function (possibly using
a bunch of UNION statements or
something), and call that function
in the IN clause. Again - this is an
untested suggestion and would need
to be worked through to determine
it's feasibility.
I hope that helps (assuming I have guessed your underlying quandary).
For future reference, it would be extremely helpful if you could include SQL script showing
your table structure and stored procedure logic so we can see what you have actually attempted. This will considerably improve the effectiveness of the answers you receive. Thanks.
P.S. The link for String Parsing actually includes a large variety of techniques for passing arrays (i.e. lists) of information to Stored Procedures - it is a very good resource for this kind of thing.
In addition to string-constants tables as Oded suggests, I have used scalar functions to encapsulate some constants. That would be better for fewer constants, of course, but their use is simple.
Perhaps a combination - string constants table with a function that takes a key and returns the string. You could even use that for localization by having the function take a 'region' and combine that with a key to return a different string!

Is there a way to find out what a stored procedure returns without running it?

I'm trying to build a designer in .NET, and would like to be able to retrieve the columns and column types of the output from a stored procedure without calling it so the designer can be used to map the output. Is this possible? I'm even willing to use an unmanaged API if necessary.
I believe what you're looking for is SET FMTONLY (Documentation).
This allows you to execute a SP (or select statement) and see what columns would be returned without actually executing the query.
This isn't possible, in general, because even a single stored procedure can return different result sets, with different columns or column data types.
In extreme cases even the number of returned result sets may depend on parameters and when the stored procedure uses dynamic sql its definitely impossible.

Sql server Code Reuse

I have a table with about 30 fields. I current have several stored procedures which access either a (aggregated) view of this table or the table itself. For many of these SPs I would like to assure that the returned records have all the same fields with the same column names. Is there a way to do this where I don't have to change 20 stored procs if I do need to change the output.
My way around it thus far is to provide clients with lists of ID which they then call SP's that return the data however this seems to be slow compared with getting the data in one shot. I have also considered using the formatting stored procs with a cursor from inside the search stored procs but was unsure if that would really buy me a whole lot.
The typical way to define a standardised and consistent data access method across multiple stored procedures in SQL Server to use Views.
Now your problem description seems to suggest that you are already using Views in order to manage your data access. If you are indeed unable to use Views for a specific reason, perhaps you can clarify the nature of your problem further for us.

How to refactor T-SQL stored procedure encapsulating it's parameters to a class

On my SQL Server 2008 I have a stored procedure with a large number of parameters.
The first part of them is used in every call and parameters from the second part are used rarely. And I can't move the logic to two different stored procedures.
Is there a way to encapsulate all this parameters to a class or struct and pass it as a stored procedure parameter?
Can I use SQL CLR. Are there other ways?
Have you tried Table Valued Parameters?
Actually, I wont use CLR function for anything which can be done effectively and easily in t-SQL. For example, last time I used CLR function is for updating a column based on some complex regex which I found pretty hard to do in t-SQL.
It sounds like your concern is with the need to specify values for each parameter. Would it work for you to just assign default values to the parameters that aren't used as often (so you don't need to pass every parameter each time the proc is called)?
A CLR type could be an option (as could XML) but I'm not sure it would be a good idea to go down that route.
If the volume of parameters is causing you problems in your application you could try one of the following two methods:
1) pass in a single parameter of XML data type that contains all of the parameters data. you could then parse out what you need. See xml (Transact-SQL).
2) create a table parameter, see Table-Valued Parameters (Database Engine), where the table is:
ParameterName sysname
DataValue sql_variant
With either of these methods, you'd more than likely need to expand them out into local variables to use them again.

Resources