Using Parameter Values In SQL Statement - sql

I am trying to write a database script (SQL Server 2008) which will copy information from database tables on one server to corresponding tables in another database on a different server.
I have read that the correct way to do this is to use a sql statement in a format similar to the following:
INSERT INTO <linked_server>.<database>.<owner>.<table_name> SELECT * FROM <linked_server>.<database>.<owner>.<table_name>
As there will be several tables being copied, I would like to declare variables at the top of the script to allow the user to specify the names of each server and database that are to be used. These could then be used throughout the script. However, I am not sure how to use the variable values in the actual SQL statements. What I want to achieve is something like the following:
DECLARE #SERVER_FROM AS NVARCHAR(50) = 'ServerFrom'
DECLARE #DATABASE_FROM AS NVARCHAR(50) = 'DatabaseTo'
DECLARE #SERVER_TO AS NVARCHAR(50) = 'ServerTo'
DECLARE #DATABASE_TO AS NVARCHAR(50) = 'DatabaseTo'
INSERT INTO #SERVER_TO.#DATABASE_TO.dbo.TableName SELECT * FROM #SERVER_FROM.#DATABASE_FROM.dbo.TableName
...
How should I use the # variables in this code in order for it to work correctly?
Additionally, do you think my method above is correct for what I am trying to achieve and should I be using NVARCHAR(50) as my variable type or something else?
Thanks

There is probably a better way to do this, but what you are probably trying to do in your example is what's called dynamic SQL where you treat the statement as a string and the execute it. This would be section #2 here:
http://www.mssqltips.com/tip.asp?tip=1160
There are some major downsides to dynamic SQL. You see a couple other approaches that might be better in that article.

If you want to execute a dynamically generated query then you have to use sp_ExecuteSQL
HTH

For the nvarchar(50) - you'd be better using sysname. This is a synonym in SQL Server (for nvarchar(128)) and represents the maximum length of an object identifier.

have a look at http://msdn.microsoft.com/en-us/library/ms188001.aspx - sp_executesql takes a parameter that is a string and executes the sql in that string. so you'd need to concatenate #SERVER_FROM and other params with the INSERT INTO part to make the entire sql statement, and then pass to sp_executesql.
nvarchar(50) is fine, unless your server/database names are longer than that :)

You can create the select statement by concatenating all the information together and then use sp_executesql
so:
sp_executesql 'INSERT INTO ' + #SERVER_TO + '.' + #DATABASE_TO +
'.dbo.TableName SELECT * FROM ' + #SERVER_FROM + '.' +
#DATABASE_FROM+'.dbo.TableName'

I like to make templates for dynamic SQL things like this - it's a lot easier to maintain complex statements and also sometimes easier to handle nested quotes - and definitely easier when terms need to be repeated in multiple places (like column lists):
DECLARE #sql AS nvarchar(max);
SET #sql = 'INSERT INTO {#SERVER_TO}.{#DATABASE_TO}.dbo.TableName
SELECT *
FROM {#SERVER_FROM}.{#DATABASE_FROM}.dbo.TableName'
SET #sql = REPLACE(#sql, '{#SERVER_TO}', QUOTENAME(#SERVER_TO))
SET #sql = REPLACE(#sql, '{#DATABASE_TO}', QUOTENAME(#DATABASE_TO))
SET #sql = REPLACE(#sql, '{#SERVER_FROM}', QUOTENAME(#SERVER_FROM))
SET #sql = REPLACE(#sql, '{#DATABASE_FROM}', QUOTENAME(#DATABASE_FROM))
EXEC(#sql)

Related

How I can use a single stored procedure for data insertion in multiple tables in SQL Server 2008?

Suppose I have many tables in my database. Every time I will insert data in any table. So, can I use a single stored procedure for all my data insertion in every table, instead of writing one stored procedure for each table?
In this scenario, each time I will pass table name and parameters dynamically to the stored procedure. If yes, can anyone give some basic idea how to perform this? If any extra information is required, please ask.
Thanks and regards,
Rizwan Gazi.
You could work with dynamic SQL and build the insert statement on the fly. THIS IS NOT RECOMMENDED but it should solve the problem you're asking about.
(I haven't run this code, but you can see what is being accomplished here with building the insert string and then executing it)
In this procedure, you pass in the table name, columns and values you care about and fire it off in a row based operation. With some minor tweaks you would be able to make it set based as well.
create procedure dbo.TableInsert
#tablename varchar(100)
, #columnlist varchar(max)
, #valueslist varchar(max)
as
begin
declare #sql varchar(max)
set #sql =
'insert into ' + #tablename
+ '(' + #columnlist + ')'
+ ' VALUES (' + #valueslist + ')'
print(#sql)
sp_executesql (#sql)
end
go
Execution would look something like this:
exec dbo.TableInsert
#tablename = 'TestTable'
, #columnlist = 'col1, col2, col3'
, #valuelist = '1,2,3'
Text insert would be a little trickier in this version since you have to wrap it around in single quotes.
exec dbo.TableInsert
#tablename = 'TestTable'
, #columnlist = 'col1, col2, col3'
, #valuelist = '''1'',''2'',''3'''
You could do something using dynamic SQL to build a query and then run it using:
EXEC SP_EXECUTESQL(#SQL)
(Assuming MS SQL Server)
Not sure I'd recommend it though and will probably be a total nightmare to test and maintain. Having different sprocs would be easier to test and maintain going forward and would perform better as the different sprocs would have separate query plans.
If you are working in code you could use a ORM to deal with basic CRUD stuff.

WHERE clause in dynamic TSQL and prevent SQL Injection

I have a stored procedure for selecting rows. I want to pass a parameter to filtering rows dynamically like this :
Create Procedure CustomerSelectAll
#FilterExpresion NVARCHAR(MAX)
DECLARE #CMD NVARCHAR(MAX)
SET #CMD = N'SELECT * FROM dbo.Customers '+#FilterExpresion;
EXEC(#CMD)
The above code works fine, but it is at risk for SQL injection, so I want to be able pass multiple columns with any WHERE statement such as:
exec CustomerSelectAll
#FilterExpresion = N' where Name = 'abc' and family = ''xyz'''
I am not aware if you can pass the entire where clause as parameter.But from the little amount of knowledge I have, I can suggest you use a sql parser to see if the where clause has just select statements and if the answer is affirmative then you can pass the where clause to your stored procedure. Hope this is of some help.

how to concatenate varying stored procedure parameters

please help me with writing this search sql stored procedure
procedure may have different number of parameters at different time
so could any body help me with writing this query. I don't know how to concatenate parameters.
i am new to stored procedure
CREATE PROCEDURE searchStudent
-- Add the parameters for the stored procedure here
#course int=null,
#branch int=null,
#admissionYear varchar(max)=null,
#passingYear varchar(max)=null,
#userName varchar(max)=null,
#sex varchar(max)=null,
#studyGap varchar(max)=null,
#firstName varchar(max)=null,
#lastName varchar(max)=null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE query STR DEFAULT null
IF #course IS NOT NULL
THEN query=
SELECT * FROM [tbl_students] WHERE
END
GO
please complete the query so that it can have parameters which are having values and can search from database on the basis of parameters value. But parameter may vary every time depends on search criteria.
You would probably need to use Dynamic SQL to achieve this. First of all I would highly recommend reading this excellent article. http://www.sommarskog.se/dynamic_sql.html
You're dynamic sql would be something like this;
Declare #query varchar(max)
Set #query = 'Select * From dbo.MyTable Where '
If #Course Is Not Null
Begin
Set #query = #query + 'Course = ' + Convert(varchar(10), #Course)
end
If #Branch Is Not Null
Begin
Set #query = #query + ' and Branch = ' + Convert(varchar(10), #Branch )
end
This is only an example! You will need to build in some checks to ensure that you have one (and only one) Where clause, you must ensure that the integer values are converted to string values correctly. You must also check that the parameters don't have any special characters that could break the dynamic sql - like an apostrophe (')
Using dynamic SQL can be painful and very difficult to get right.
Good luck!
The key with a dynamic search conditions is to make sure an index is used, instead of how can I easily reuse code, eliminate duplications in a query, or try to do everything with the same query. Here is a very comprehensive article on how to handle this topic:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
It covers all the issues and methods of trying to write queries with multiple optional search conditions. This main thing you need to be concerned with is not the duplication of code, but the use of an index. If your query fails to use an index, it will preform poorly. There are several techniques that can be used, which may or may not allow an index to be used.
here is the table of contents:
Introduction
The Case Study: Searching Orders
The Northgale Database
Dynamic SQL
Introduction
Using sp_executesql
Using the CLR
Using EXEC()
When Caching Is Not Really What You Want
Static SQL
Introduction
x = #x OR #x IS NULL
Using IF statements
Umachandar's Bag of Tricks
Using Temp Tables
x = #x AND #x IS NOT NULL
Handling Complex Conditions
Hybrid Solutions – Using both Static and Dynamic SQL
Using Views
Using Inline Table Functions
Conclusion
Feedback and Acknowledgements
Revision History
Sorry, I am having trouble understanding what you are asking. Do you mean the consumer of the sproc may specify some arbitrary subset of the parameters and you want to filter on those?
Assuming the above you have 2 options.
1.
use a where clause something like this:
WHERE ([tbl_students].firstName = ISNULL(#firstname,firstName)
AND ([tbl_students].lastName = ISNULL(#lastName ,lastName )
etc.
What this does is check if your parameter has a value, and, if so, it will compare it to the column. If the param is null, then it will compare the column to itself, which will never filter anything out.
use dynamic sql in your sproc and just include the line of the where clause you want if the param is not null.

In SQL Server, how do I create a reference variable to a table?

I'm currently using sp_executesql to execute a T-SQL statement with a dynamic table name. However, it is really ugly to see something like:
set #sql = 'UPDATE '+Table_Name+' SET ... WHERE '+someVar+' = ... AND '+someVar2' = ...'
sp_executesql #sql
What I would rather like to have is a TABLE variable of which is a reference to a table, so I could do for example:
UPDATE TableRef SET ... WHERE ...
Because when I have really long T-SQL statements it gets really hard to read due to the format of it within a string.
Any suggestions would be helpful.
Why don't you pass the parameters to sp_executeSQL instead?
http://msdn.microsoft.com/en-us/library/ms188001.aspx
I'd also have a read of this article too http://www.sommarskog.se/dynamic_sql.html
You can't. If you want to use a dynamic table name in your SQL, you have to concatenate it into your string.
If you have a lot of references to the table name within your query, you can shorten it by aliasing the table name, and for all other instances, use the alias.
e.g.
SET #SQL = 'UPDATE t SET.... FROM ' + #TableName + ' t WHERE ....'
Just be very very careful when using dynamic SQL like this. Make sure you guard yourself against SQL injection.

SQL Update columns passing into the query the column name and value

I have the following code:
UPDATE myTable
SET Col1 = #Value
However, I have a table that has over a 100 columns and want to be able to specify a column name by passing the name into the query similar to:
UPDATE myTable
SET #ColName = #Value
When I do this I get an error. Is there a good solution to this? Its probably something simple!
Thank you in advanced.
You'll have to use dynamic SQL, and write it to make sure you don't let Little Bobby Tables in. Something like this:
DECLARE #sql NVARCHAR(500)
SET #sql = N'UPDATE myTable SET ' + QUOTENAME(#colName) + ' = #pUpdateVal'
EXEC sp_ExecuteSQL #sql, '#pUpdateVal NVARCHAR(20)', #value
Make sure you change the type of #pUpdateVal to something appropriate for your environment, but this will mitigate the risk of injection attacks.
You'd have to revert to dynamic SQL to do this.
Agreed with the others, you'll need dynamic SQL for this; you can't define object names at run time in native SQL. For a full discussion on dynamic SQL see http://www.sommarskog.se/dynamic_sql.html