views:

1039

answers:

6

Hi,

I have a very simple question. I have 15 stored procedures that return data from a common table, then join that table with a specific table to retrieve inventory.

Ex.

Common: tblCommon
Specific: tblSpecific

Is there i was i can pass the name "tblSpecific" into a single stored procedure as a variable, like this:

SELECT ....
FROM tblCommon c
INNER JOIN @TABLE s on c.primaryKey = s.foreignKey

Thanks!

+2  A: 

Yep you can generate a sql statement dynamically and then exec it.

e.g.

DECLARE @specificTableName nvarchar(50)
DECLARE @specificColumnName nvarchar(50)

SET @specificTableName = 'tblSpecific'
SET @specificColumnName = 'colSpecific'

DECLARE @sql nvarchar(4000)

set @sql = 'SELECT ... FROM tblCommon c INNER JOIN ' + 
@specificTableName + ' s ON c.PrimaryKey = s.' + @specificColumnName 


exec (@sql)
Eoin Campbell
+4  A: 

The way you do this is with dynamically generated SQL which is run through the sp_executesql() stored procedure.

In general you pass in your required table name to your master procedure, build an ncharvar string of the SQL you want to execute, and pass that to sp_executesql.

The curse and blessing of Dynamic SQL is about the best page I have seen for describing all the in's and out's.

One of the biggest gotchas is that if you use dynamic SQL then the user who calls your stored procedure not only has to have execute permission on that procedure, but also has to have permission to access the underlying tables. The link I gave also describes how to get around that issue.

Peter M
A: 

An alternative, if the amount of data isn't too large you may want want to consider a user defined function, which can return a table variable which you could use to join to.

SELECT ....
FROM tblCommon c
INNER JOIN dbo.SomeFuntionThatReturnsData(@someparam) s on c.primaryKey = s.foreignKey
duckworth
Thanks, that is probably as close as I'm going to get.
As you can't use a table name as a parameter, then you will still have to explicitly write out all of your SQL in individual statements at some point.
Peter M
Yeah, but my point was the funtion might be able to replace the 15 procs and used to return a common table variable to join to.
duckworth
A: 

Hi,

Thanks for the suggestions, but the last thing I want to do is concentrate strings, I created the stored procedures in the first place to eliminate that. Now you've just described moving them to a different part of the app.

Thanks

Unfortunately you can't use a table name as a parameter to an SQL query. Been there done that last week ;-)
Peter M
A: 

Dynamic SQL is dangerous. You never want to substitute passed values directly into an sql string. Fortunately, it sounds like you already know that.

Unfortunately, in this case you've discovered the problem that you can't use an sql parameter for the table name. So, what to do? You don't want to use the passed value in dynamically generated sql but you can't put it in a query in the normal safe way.

The answer is a lookup table. Create a 'tables' table that holds the name of each of your specific tables. It should look kind of like this:

CREATE TABLE [tables] (table_name sysname)

Then you can write a query that looks something like this:

SELECT @tblSpecific = table_name FROM [tables] WHERE table_name = @tblSpecific

Now you just have to check whether @tblSpecific is NULL. If it's not, then it's safe to use in a dynamic sql statement (and dynamic sql is ultimately your only option here: even the user defined function has you doing that at some level).

Oh, and one more thing-- my choice of names and types for the lookup table is not an accident. The SQL Standard already has a table like this (well, a view anyway). Just use INFORMATION_SCHEMA.Tables.

Joel Coehoorn
That's just reactionary to say NEVER. You never want to do so *IF* the value is gathered from a user screen... but if you create the domain for that variable it's safe.. just as safe as if he wrote one query per table and put them in a case statement. Some people have no sense of moderation.
A: 

I would save them each as a distinct stored procedure.

As much as possible, I like to keep my stored procedures bare and simple. They're hard enough to grok with a glance, because the expressions stretch out so much anyway, and adding a bunch of procedural code intermingled with the fragments of declarative code just makes it more difficult.

You're either going to end up with a list of 15 invocations of a more complex stored procedure with parameters, or you're going to end up with an equivalent list of simpler stored procedures. And if your parameter is a table name, it won't be the kind of parameterized sp that executes efficiently. As for the table driven approach, it is still the less efficient and more dangerous dynamic stored procedure. The table entries are as likely to be mis-entered, except in a table, any table-name errors would be even less visible. And coupling has gone up, and gohesiveness has gone down (both headed in the wrong direction).

le dorfier
Amen... People get lost in the idea of non-repeating code. "If I put it in one place it will be really cool." The downside is that when changes need to be made you'll need to fix it in a few places but there's a big chance that one of these 15 tables will look different and need to come out anyways.
This is one of the many ways that good coding style for declarative code isn't equivalent to good coding style for procedural code. There aren't many transferable skills between the two. IOW, excellent procedural skills doesn't imply much about how good you will be at SQL.
le dorfier