I have the following query which takes the XML input and stores them into temp tables.
I need to make the query dynamic or a function which will adjust to any table or column number modification dynamically.How do I do that:
DECLARE #sXML NVARCHAR(4000)
DECLARE #hDoc INT
SET #sXML = '
<Root>
<Item>
<Key>1</Key>
<Test1>A</Test1>
<Test2>A2</Test2>
</Item>
<Item>
<Key>2</Key>
<Test1>B</Test1>
<Test2>B3</Test2>
</Item>
</Root>
'
CREATE TABLE #tabletest
(
[Key] INT,
Test1 NVARCHAR(50),
Test2 NVARCHAR(50)
)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #sXML
INSERT INTO #tabletest SELECT * FROM OPENXML (#hDoc, '/Root/Item', 2) WITH #tabletest
EXEC sp_xml_removedocument #hDoc
select * from #tabletest
DROP TABLE #tabletest
To create Dynamic SQL you need to build up the query as a string. Using If Statements and other logic to add your variables...etc.
Declare a text variable and use this to concatenate together your desired SQL.
You can then execute this code using the "EXEC" command
Example:
DECLARE #SQL VARCHAR(100)
DECLARE #TableOne VARCHAR(20) = 'TableOne'
DECLARE #TableTwo VARCHAR(20) = 'TableTwo'
DECLARE #SomeInt INT
SET #SQL = 'INSERT INTO '
IF (#SomeInt = 1)
SET #SQL = #SQL + #TableOne
IF (#SomeInt = 2)
SET #SQL = #SQL + #TableTwo
SET #SQL = #SQL + ' VALUES....etc'
EXEC (#SQL)
However, something you should really watch out for when using this method is a security problem called "SQL Injection".
You can read up on that here:
http://msdn.microsoft.com/en-gb/library/ms161953(v=sql.105).aspx
One way to guard against SQL injection is to validate against it in your C# code before passing the variables to SQL-Server.
An alternative way (or probably best used in conjecture) is instead of using the "EXEC" command, use a built in stored procedure called "sp_executesql".
Details of which can be found here: http://msdn.microsoft.com/en-gb/library/ms188001.aspx
How it is used is detailed here: http://msdn.microsoft.com/en-gb/library/ms175170(v=sql.105).aspx
You'll have to build your SQL slightly differently and pass your parameters to the stored procedure as well as the #SQL.
Related
As I have seen so far, people suggested using dynamic SQL.
For example:
How to pass schema as parameter to a stored procedure in sql server?
How to pass schema name as parameter in stored procedure
However, dynamic SQL has the risk of SQL injection. Hence, I want to know if there are any other safe alternatives?
Basically, this stored procedure that I am creating will be called at runtime. There will be 2 possible schemas to be passed in. And the table name will be passed in as well.
Something like below: (It does not work)
CREATE PROCEDURE [EFM].[usp_readApexTable]
#SCHEMANAME VARCHAR(20) = NULL,
#TABLENAME VARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM [#SCHEMANAME].[#TABLENAME];
END
GO
This is just an example of READ action. My plan is to create for CRUD, which requires 4 different stored procedures.
You can use QUOTENAME to avoid any SQL injection and build your dynamic query like the following:
CREATE PROCEDURE [EFM].[usp_readApexTable]
#SCHEMANAME VARCHAR(20) = NULL,
#TABLENAME VARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL VARCHAR(MAX)=N'SELECT * FROM '
+ QUOTENAME(#SCHEMANAME) + '.' + QUOTENAME(#TABLENAME)
EXEC (#SQL)
END
GO
Note: If you have any plan to add parameters also for your WHERE clause, in that case QUOTENAME will not help much, I suggest to to use sp_executesql by passing appropriate parameters used in WHERE clause.
Still you need to use QUOTENAME for schema and table name as SQL excepts it only as literal, you can't use variable names for table and schema.
For example.
declare #sql nvarchar(max)
set #sql = N'select * from ' + quotename(#SCHEMANAME ) + '.' + quotename(#TABLENAME )
+ ' where (City = #City)'
exec sp_executesql
#sql,
N'#City nvarchar(50)',
#City
You can find more details here
You need to use dynamic sql to do this operation
CREATE PROCEDURE [EFM].[usp_readApexTable]
#SCHEMANAME VARCHAR(20) = NULL,
#TABLENAME VARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sqlCommand nvarchar(MAX)
SET #sqlCommand='SELECT * FROM ['+#SCHEMANAME+'].['+#TABLENAME+'];'
--Create Your Temp Table where you can set the records after executing the dynamic query
CREATE TABLE #tmpTbl(
Column1 [datatype]
Column2 [datatype]
.
.
ColumnN
)
INSERT INTO #tmpTbl EXEC sp_executesql #sqlCommand --Copy data to #tmpTbl table
SELECT * FROM #tmpTbl
DROP TABLE #tmpTbl
END
GO
I want to create a stored procedure with dynamic parameters. One of these parameters is a table type
CREATE TYPE [dbo].[IdTable] AS TABLE ([Id] [int] NULL)
GO
CREATE PROCEDURE [dbo].[SP_deleteCells]
#table IdTable READONLY,
#tableName NVARCHAR(50),
#fieldName NVARCHAR(50),
#result BIT OUTPUT
AS
DECLARE #SQL NVARCHAR(500);
SET #SQL='delete from TBL_CustomerTerminal where ID in (select ID from #table)'
EXEC (#SQL);
SET #result = ##ROWCOUNT;
How can I exec this code without errors?? Right now, I get:
Must declare the table variable "#table"
Use sp_executesql
exec sp_executesql N'delete from TBL_CustomerTerminal where ID in (select ID from #table)'
, N'#table dbo.IdTable readonly' /* parameter declaration for sp_executesql */
, #table /* pass the parameters */
It doesn't seem that you need dynamic SQL for the query above. But I assume it is just a sample.
The dynamic SQL query has it's own code visibility. It can't see any variable outside of the locally defined variables. If you want to pass parameters to your query you need to use sp_executesql instead of EXEC.
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql
I want to make a EXEC in my sql with Transact-SQL, like:
set #name = 'test'
set #sql = 'insert into TempTable values('+#name+')'
EXEC( #sql)
but i can't insert a varchar in the sql string because i can't put ' into the string so it to knows that #name is a varchar.
first declare the variable first with declare , set and then u can use it.
below the complete code :
DECLARE #name VARCHAR (500)
SET #name = 'test';
set #sql = 'insert into TempTable values('''+#name+''')'
EXEC( #sql)
use (''') three quote to add your varchar.
A simple insert statement like this does not need to executed using Dynamic SQL. you can easily achieve the same using the query below.
DECLARE #name VARCHAR (500)
SET #name = 'test';
insert into TempTable values(#name)
You can refer to the link below for more details on issues related to dynamic sql.
http://www.sommarskog.se/dynamic_sql.html
Please forget using EXEC when you are working with dynamic queries. In SQL Server you should use sp_executesql
DECLARE #name VARCHAR(500);
SET #name = 'test';
DECLARE #query = NVARCHAR(MAX) = 'INSERT INTO TempTable VALUES (#name)';
EXEC sp_executesql
#stmt = #query,
#params = N'#name VARCHAR(500)',
#name = #name
With this
You can avoid unnecessary type conversions (INT -> VARCHAR, etc)
Native data types could be passed
A bit more secure (will not solve all the problems, but a bit bette, than injecting variable values into the query string)
I am trying to write a custom stored procedure to carry out a select into operation. I want to copy a table (or some columns from a table) from one database to another. I am using SQL Server 2012
CREATE Procedure select_into
AS
Begin
#selection varchar(128),
#newtabname varchar(128)
#fromtabname varchar(128)
Select selection,
INTO table1,
FROM table2,
WHERE selection = #selection AND table1 = #newtabname AND table2 =#fromtabname;
go
EXEC select_into, Ecode, relational_db.dbo.work, dbo.Work_Data;
I get an error message indicating a syntax error near the "." in relational_db.dbo.work.
I would appreciate any help in getting this right
You have a missing comma in parameter list and wrong syntax for procedure declaration. It should be::
CREATE Procedure select_into
(
#selection varchar(128),
#newtabname varchar(128),
#fromtabname varchar(128)
)
AS
Begin
BUT, in addition your syntax for an INSERT INTO contains extra commas and you cannot perform dynamic T-SQL that way.
Can I suggest you first learn TSQL's syntax for SQL Server.
Try something like this ...
CREATE Procedure select_into
#selection NVARCHAR(128),
#newtabname NVARCHAR(128),
#fromtabname NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'Select ' + QUOTENAME(#selection) +
N' INTO ' + QUOTENAME(#newtabname) +
N' FROM ' + QUOTENAME(#fromtabname)
EXECUTE sp_executesql #sql
END
Is this incorrect, can't we pass the table name to a select query dynamically?
This is giving me a error 'Must declare the table variable #TblName'
DECLARE #TblName VARCHAR(30)
SET #TblName = 'User'
SELECT *
FROM #TblName
You need to create a dynamic SQL query, preferably using the QUOTENAME function. You can avoid any issues from malicious input by using QUOTENAME function.
Here is a sample script that illustrates how to query a table by creating a dynamic SQL query by passing in a table name. You can change the table name by value to the variable #tablename.
Create and insert script for sample:
CREATE TABLE sample
(
id INT NOT NULL
);
INSERT INTO sample (id) VALUES
(1),
(2),
(3),
(4),
(5),
(6);
Dynamic SQL script:
DECLARE #execquery AS NVARCHAR(MAX)
DECLARE #tablename AS NVARCHAR(128)
SET #tablename = 'sample'
SET #execquery = N'SELECT * FROM ' + QUOTENAME(#tablename)
EXECUTE sp_executesql #execquery
Demo:
Click here to view the demo in SQL Fiddle.
Suggested read:
The Curse and Blessings of Dynamic SQL
you have to use dynamic sql execution
wrap your statement in #selectstr
use exec sp_executesql #selectstr
You can do this thing by using dynamic query, Check below
DECLARE #TblName VARCHAR(30)
DECLARE #vQuery NVARCHAR(100)
SET #TblName = 'User'
SET #vQuery = 'SELECT * FROM ' + #TblName
EXECUTE sp_executesql #vQuery