转自:http://www.sqlusa.com/bestpractices/training/scripts/dynamicsql/

Dynamic SQL & Stored Procedure Usage in T-SQL

Important security article related to dynamic SQL: How To: Protect From SQL Injection in ASP.NET

------------

-- Dynamic SQL QUICK SYNTAX

------------

USE AdventureWorks2008;

EXEC ('SELECT * FROM Sales.SalesOrderHeader')

DECLARE @DynamicSQL varchar(256); SET @DynamicSQL='SELECT * FROM Sales.SalesOrderHeader'

EXEC (@DynamicSQL)

GO

DECLARE @DynamicSQL varchar(256), @Table sysname;

SET @DynamicSQL='SELECT * FROM'; SET @Table = 'Sales.SalesOrderHeader'

SET @DynamicSQL = @DynamicSQL+' '+@Table

PRINT @DynamicSQL  -- for testing & debugging

EXEC (@DynamicSQL)

GO

-- Dynamic SQL for rowcount in all tables

DECLARE @DynamicSQL nvarchar(max), @Schema sysname, @Table sysname;

SET @DynamicSQL = ''

SELECT @DynamicSQL = @DynamicSQL + 'SELECT '''+QUOTENAME(TABLE_SCHEMA)+'.'+

QUOTENAME(TABLE_NAME)+''''+

'= COUNT(*) FROM '+ QUOTENAME(TABLE_SCHEMA)+'.'+QUOTENAME(TABLE_NAME) +';'

FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'

PRINT @DynamicSQL                 -- test & debug

EXEC sp_executesql @DynamicSQL    -- sql server sp_executesql

-- Equivalent code using the undocumented sp_MSforeachtable

EXEC sp_MSforeachtable 'select ''?'', count(*) from ?'

------------

-- Dynamic sort with collation - Dynamic ORDER BY - SQL dynamic sorting

DECLARE @SQL nvarchar(max)='SELECT FullName=FirstName+'' ''+Lastname

FROM AdventureWorks2008.Person.Person

ORDER BY LastName '

DECLARE @Collation nvarchar(max) = 'COLLATE SQL_Latin1_General_CP1250_CS_AS'

SET @SQL=@SQL + @Collation

PRINT @SQL

EXEC sp_executeSQL @SQL

------------

-- sp_executeSQL usage with input and output parameters

DECLARE @SQL NVARCHAR(max), @ParmDefinition NVARCHAR(1024)

DECLARE @Color varchar(16) = 'Blue', @LastProduct varchar(64)

SET @SQL =       N'SELECT @pLastProduct = max(Name)

FROM AdventureWorks2008.Production.Product

WHERE Color = @pColor'

SET @ParmDefinition = N'@pColor varchar(16),

@pLastProduct varchar(64) OUTPUT'

EXECUTE sp_executeSQL

@SQL,

@ParmDefinition,

@pColor = @Color,

@pLastProduct=@LastProduct OUTPUT

SELECT Color=@Color, LastProduct=@LastProduct

/* Color    LastProduct

Blue  Touring-3000 Blue, 62 */

----------

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The following dynamic SQL scripts demonstrate:

1. Dynamic SQL stored procedure

2. Dynamic SQL with OUTPUT parameter

3. Stored procedure with dynamic SQL WHILE loop

4. Dynamic SQL with using parent's #temptable

5. Dynamic SQL for dynamic PIVOT query

6. Dynamic stored procedure with output parameter

7. WHERE clause with dynamic set of predicates

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

IMPORTANT SECURITY ARTICLE:

Is Dynamic SQL in Your Stored Procedures Vulnerable to SQL Injection?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- FIRST EXAMPLE - dynamic stored procedure for customer list
USE Northwind;

GO

-- DROP stored procedure if exists to make CREATE work

IF EXISTS ( SELECT *

FROM sys.objects

WHERE object_id = OBJECT_ID(N'[dbo].[CustomerListByState]')

AND TYPE IN (N'P',N'PC'))

DROP PROCEDURE [dbo].[CustomerListByState]

GO

-- Sproc (stored procedure) with dynamic SQL

/***** DEMO ONLY - This sproc is vulnerable to SQL Injection Attack *****/

-- List splitter and JOIN is the preferred solution

CREATE PROCEDURE CustomerListByState

@States VARCHAR(128)

AS

BEGIN

SET NOCOUNT ON

DECLARE @SQL NVARCHAR(MAX) -- alternate nvarchar(1024)

-- Dynamic query assembly with string concatenation

SET @SQL = 'select Region, CustomerID, CompanyName, ContactName, Phone

from Customers where Region IN (' + @States + ')' +

' order by Region, CompanyName'

PRINT @SQL -- for testing & debugging

/* Assembled code

select Region, CustomerID, CompanyName, ContactName, Phone

from Customers where Region IN ('WA', 'OR', 'ID', 'CA')

order by Region, CompanyName

*/

EXEC sp_executeSQL @SQL

END

GO

-- Execute dynamic SQL stored procedure script

DECLARE @States VARCHAR(100)

SET @States = '''WA'', ''OR'', ''ID'', ''CA'''

EXEC CustomerListByState @States

GO /* Results

Region CustomerID CompanyName ContactName Phone
CA LETSS Let's Stop N Shop Jaime Yorres (415) 555-5938
ID SAVEA Save-a-lot Markets Jose Pavarotti (208) 555-8097
OR GREAL Great Lakes Food Market Howard Snyder (503) 555-7555
OR HUNGC Hungry Coyote Import Store Yoshi Latimer (503) 555-6874
OR LONEP Lonesome Pine Restaurant Fran Wilson (503) 555-9573
OR THEBI The Big Cheese Liz Nixon (503) 555-3612
WA LAZYK Lazy K Kountry Store John Steel (509) 555-7969
WA TRAIH Trail's Head Gourmet Provisioners Helvetius Nagy (206) 555-8257
WA WHITC White Clover Markets Karl Jablonski (206) 555-4112

*/

-- SECOND EXAMPLE - search names in Person.Person table

-- Dynamic SQL with input and output parameters

USE AdventureWorks2008;

DECLARE  @ParmDefinition NVARCHAR(1024) = N'@FirstLetterOfLastName char(1),

@LastFirstNameOUT nvarchar(50) OUTPUT'

DECLARE @FirstLetter CHAR(1) = 'P', @LastFirstName NVARCHAR(50)

DECLARE @SQL NVARCHAR(MAX) = N'SELECT @LastFirstNameOUT = max(FirstName)

FROM Person.Person'+CHAR(13)+

'WHERE left(LastName,1) = @FirstLetterOfLastName'

PRINT @SQL+CHAR(13)     -- test & debug

PRINT @ParmDefinition    -- test & debug

EXECUTE sp_executeSQL

@SQL,

@ParmDefinition,

@FirstLetterOfLastName = @FirstLetter,

@LastFirstNameOUT=@LastFirstName OUTPUT

SELECT

[Last First Name] = @LastFirstName,

Legend='of last names starting with',

Letter=@FirstLetter

GO

/* Results

Last First Name   Legend                        Letter

Zoe               of last names starting with   P

*/

-- THIRD EXAMPLE - SPROC to enumerate all objects in databases

-- Return objects count in all databases on the server

-- Dynamic SQL stored procedure with cursor loop

-- QUOTENAME function is used to build valid identifiers

USE AdventureWorks;

GO

IF EXISTS (SELECT *

FROM   sys.objects

WHERE  object_id = OBJECT_ID(N'[dbo].[sprocObjectCountsInAllDBs]')

AND TYPE IN (N'P',N'PC'))

DROP PROCEDURE [dbo].[sprocObjectCountsInAllDBs]

GO

CREATE PROC sprocObjectCountsInAllDBs

AS

BEGIN

DECLARE  @dbName      SYSNAME,

@ObjectCount INT

DECLARE  @SQL NVARCHAR(MAX)

DECLARE  @DBObjectStats  TABLE(

DBName    SYSNAME,

DBObjects INT

)

DECLARE curAllDBs CURSOR  FOR

SELECT   name

FROM     MASTER.dbo.sysdatabases

WHERE    name NOT IN ('master','tempdb','model','msdb')

ORDER BY name

OPEN curAllDBs

FETCH  curAllDBs

INTO @dbName

WHILE (@@FETCH_STATUS = 0) -- Loop through all db-s

BEGIN

-- Build valid yet hard-wired SQL statement

SET @SQL = 'select @dbObjects = count(*)' + char(13) + 'from ' +

QuoteName(@dbName) + '.dbo.sysobjects'

PRINT @SQL -- Use it for debugging

/*

select @dbObjects = count(*)

from [AdventureWorks].dbo.sysobjects

*/

-- Dynamic call for query execution with output parameter(s)

EXEC sp_executesql @SQL, N'@dbObjects int output',

@dbObjects = @ObjectCount output

INSERT @DBObjectStats SELECT @dbName, @ObjectCount

FETCH  curAllDBs

INTO @dbName

END -- while

CLOSE curAllDBs

DEALLOCATE curAllDBs

-- Return results

SELECT * FROM @DBObjectStats ORDER BY DBName

END

GO

-- Execute stored procedure

EXEC sprocObjectCountsInAllDBs

GO

/* Partial results

DBName                  DBObjects

AdventureWorks          604

AdventureWorks2008      646

AdventureWorksDW        151

AdventureWorksDW2008    164

AdventureWorksLT        158

AdventureWorksLT2008    158

*/

/* FOURTH EXAMPLE - automatic T-SQL code generation
        for datetime conversion from style 0 to 14 */

USE AdventureWorks2008;

DECLARE  @I INT = -1

DECLARE  @SQLDynamic NVARCHAR(1024)

-- Temporary table is used for data sharing between parent & child processes

-- This is the parent process; the child process is the dynamic SQL execution

CREATE TABLE #SQL (

STYLE  INT,

[SQL]  VARCHAR(256),

Result VARCHAR(32))

-- Loop on @I from 0 to 13

WHILE (@I < 14)

BEGIN

SET @I += 1

-- Store query and dynamic results in temporary table

INSERT #SQL (STYLE, [SQL])

SELECT @I,

'SELECT ' + 'CONVERT(VARCHAR, GETDATE(), ' +

CONVERT(VARCHAR,@I) + ')'

-- Build dynamic sql statement

SET @SQLDynamic = 'UPDATE #SQL SET Result=(SELECT  CONVERT(VARCHAR,

GETDATE(), ' + CONVERT(VARCHAR,@I) + ')) WHERE STYLE=' +

CONVERT(VARCHAR,@I)

PRINT @SQLDynamic

/*

UPDATE #SQL SET Result=(SELECT  CONVERT(VARCHAR,

GETDATE(), 0)) WHERE STYLE=0

*/

EXEC sp_executeSQL  @SQLDynamic

END

-- Return results from temporary table

SELECT * FROM   #SQL

DROP TABLE #SQL

GO

/* Partial results

STYLE SQL                                       Result

0     SELECT CONVERT(VARCHAR, GETDATE(), 0)     Mar 14 2009  6:10AM

1     SELECT CONVERT(VARCHAR, GETDATE(), 1)     03/14/09

2     SELECT CONVERT(VARCHAR, GETDATE(), 2)     09.03.14

*/

-- FIFTH EXAMPLE - dynamic pivot crosstab query

------------

-- T-SQL Dynamic Pivot Crosstab Report - Column header YYYY is dynamically assembled

------------

USE AdventureWorks

GO

DECLARE  @YearList  AS  TABLE(

YYYY INT    NOT NULL    PRIMARY KEY

)

DECLARE  @DynamicSQL  AS NVARCHAR(MAX)

INSERT INTO @YearList

SELECT DISTINCT YEAR(OrderDate)

FROM   Sales.SalesOrderHeader

DECLARE  @ReportColumnNames  AS NVARCHAR(MAX),

@IterationYear      AS INT

SET @IterationYear = (SELECT MIN(YYYY)

FROM   @YearList)

SET @ReportColumnNames = N''

-- Assemble pivot list dynamically

WHILE (@IterationYear IS NOT NULL)

BEGIN

SET @ReportColumnNames = @ReportColumnNames + N',' + QUOTENAME(CAST(@IterationYear AS NVARCHAR(10)))

SET @IterationYear = (SELECT MIN(YYYY)

FROM   @YearList

WHERE  YYYY > @IterationYear)

END

SET @ReportColumnNames = SUBSTRING(@ReportColumnNames,2,LEN(@ReportColumnNames))

PRINT @ReportColumnNames

-- [2001],[2002],[2003],[2004]

SET @DynamicSQL = N'SELECT * FROM (SELECT [Store (Freight Summary)]=s.Name,

YEAR(OrderDate) AS OrderYear,

Freight = convert(money,convert(varchar, Freight))

FROM Sales.SalesOrderHeader soh

INNER JOIN Sales.Store s

ON soh.CustomerID = s.CustomerID) as Header

PIVOT (SUM(Freight)    FOR OrderYear

IN(' + @ReportColumnNames + N'))  AS Pvt

ORDER BY 1'

PRINT @DynamicSQL -- Testing & debugging

/*

SELECT * FROM (SELECT [Store (Freight Summary)]=s.Name,

YEAR(OrderDate) AS OrderYear,

Freight = convert(money,convert(varchar, Freight))

FROM Sales.SalesOrderHeader soh

INNER JOIN Sales.Store s

ON soh.CustomerID = s.CustomerID) as Header

PIVOT (SUM(Freight)    FOR OrderYear

IN([2001],[2002],[2003],[2004]))  AS Pvt

ORDER BY 1

*/

-- Execute dynamic sql

EXEC sp_executesql   @DynamicSQL

GO -- Partial results

Store (Freight Summary) 2001 2002 2003 2004
A Bike Store 921.55 1637.24 NULL NULL
A Great Bicycle Company 142.08 114.34 15.24 NULL
A Typical Bike Shop 976.61 1529.08 NULL NULL
Acceptable Sales & Service 12.58 25.17 NULL NULL
Accessories Network NULL NULL 24.72 43.06
Acclaimed Bicycle Company NULL NULL 190.01 53.8
Ace Bicycle Supply NULL 21.46 21.67 69.46

------------

-- SIXTH EXAMPLE - dynamic stored procedure with output

-- SQL Server dynamic SQL stored procedure to find size for all databases

CREATE PROC sprocSizeForAllDBs

AS

BEGIN

DECLARE  @dbName      SYSNAME,

@ObjectSize INT

DECLARE  @SQL NVARCHAR(MAX)

DECLARE  @DBSizes  TABLE(

DBName             SYSNAME,

DBSizeinMB       MONEY

)

DECLARE curAllDBs CURSOR  FOR

SELECT   name

FROM     MASTER.dbo.sysdatabases

WHERE    name NOT IN ('master','tempdb','model','msdb')

ORDER BY name

OPEN curAllDBs

FETCH  curAllDBs

INTO @dbName

WHILE (@@FETCH_STATUS = 0) -- Loop through all db-s

BEGIN

-- Build valid yet hard-wired SQL statement

SET @SQL = 'select @DBSize = 0.0078125 * sum(size) ' + char(13) +

'from ' + QuoteName(@dbName) + '.dbo.sysfiles'

PRINT @SQL -- test & debug

/*

select @DBSize = 0.0078125 * sum(size)

from [AdventureWorks].dbo.sysfiles

*/

-- Dynamic call for query execution with output parameter(s)

EXEC sp_executesql  @SQL ,

N'@DBSize Money output' ,

@DBSize = @ObjectSize OUTPUT

INSERT @DBSizes

SELECT @dbName,  @ObjectSize

FETCH  curAllDBs

INTO @dbName

END -- while

CLOSE curAllDBs

DEALLOCATE curAllDBs

INSERT @DBSizes  -- total size

SELECT 'Total Space Used', SUM(DBSizeinMB) FROM @DBSizes

-- Return results

SELECT *

FROM     @DBSizes

ORDER BY DBSizeinMB DESC

END -- sproc

GO

EXEC sprocSizeForAllDBs

/*

DBName                    DBSizeinMB

....

AdventureWorks            172.00

AdventureWorks2008        182.00

AdventureWorksDW          69.00

AdventureWorksDW2008      87.00

.....

*/

------------

-- SEVENTH EXAMPLE - dynamic WHERE clause

-- Dynamic SQL logic to search a set of keywords in text

USE tempdb;

CREATE TABLE [Text] (Line nvarchar(max))

INSERT [Text] VALUES ('microsoft.com SQL web page quote: Line-of-business applications (LOB) are the critical

link between the IT department and the business. The ability to securely and reliably

store, centralize, manage and distribute data out to users is key to these

LOB applications. SQL Server 2008 provides businesses with a high

performance database platform that’s reliable, scalable, and easy to manage.

SQL Server 2008 R2 builds on the 2008 release and helps IT departments provide

even more cost-effective scalability on today’s most advanced hardware platforms

using familiar SQL Server administration tools.')

DECLARE @Keyword TABLE ( Search varchar(32))

INSERT @Keyword VALUES

('reliable'),

('scalability'),

('centralize')

-- Dynamic SQL string variable

DECLARE @SQL nvarchar(max) = 'SELECT Result=''FOUND''

FROM [Text]

WHERE 1 != 1'

-- Cursor WHILE loop to add all search word predicates to WHERE clause

/******* THIS IS THE DYNAMIC PART *********/

DECLARE @Search varchar(32)

DECLARE curKeyword CURSOR FOR SELECT Search FROM @Keyword

OPEN curKeyword

FETCH NEXT FROM curKeyword into @Search

WHILE (@@FETCH_STATUS = 0)

BEGIN

SET @SQL=@SQL+CHAR(13)+'     OR PATINDEX(''%'+@Search+'%'', Line) > 0'

FETCH NEXT FROM curKeyword into @Search

END -- while

PRINT @SQL

/*

SELECT Result='FOUND'

FROM [Text]

WHERE 1 != 1

OR PATINDEX('%reliable%', Line) > 0

OR PATINDEX('%scalability%', Line) > 0

OR PATINDEX('%centralize%', Line) > 0

*/

EXEC sp_executeSQL @SQL

-- FOUND

-- Cleanup

DROP TABLE [Text]

------------

SQL Server Dynamic SQL & Dynamic SQL Stored Procedure links with more examples:

http://www.sqlusa.com/bestpractices/dynamicsql/

The Curse and Blessings of Dynamic SQL

How to search using all or partial columns with Dynamic SQL while avoiding SQL Injection

The Best SQL Server Training in the World

[转]Dynamic SQL & Stored Procedure Usage in T-SQL的更多相关文章

  1. Difference between Stored Procedure and Function in SQL Server

    Stored Procedures are pre-compile objects which are compiled for first time and its compiled format ...

  2. SQL Stored Procedure and Function

    Anything can be programmable with defined syntax and common lib. )) -- Add the parameters for the st ...

  3. SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems) 实现代码(SQL Codes) 方法一:拼接SQL: 方法二: ...

  4. SQL Server——存储过程(Stored Procedure)、事物、触发器

    存储过程(proc 或 procedure) 存储过程(Stored Procedure),计算机用语,是一组为了完成特定功能的SQL语句集,是利用SQL Server所提供的Transact-SQL ...

  5. java当中JDBC当中请给出一个sql server的stored procedure例子

    3.sql server的stored procedure例子: import java.sql.*;public class StoredProc0 {public static void main ...

  6. Modify a Stored Procedure using SQL Server Management Studio

    In Object Explorer, connect to an instance of Database Engine and then expand that instance. Expand  ...

  7. Stored Procedure 里的 WITH RECOMPILE 到底是干麻的?

    在 SQL Server 创建或修改「存储过程(stored procedure)」时,可加上 WITH RECOMPILE 选项,但多数文档或书籍都写得语焉不详,或只解释为「每次执行此存储过程时,都 ...

  8. JDBC连接执行 MySQL 存储过程报权限错误:User does not have access to metadata required to determine stored procedure parameter types. If rights can not be granted,

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  9. [转]Easy Stored Procedure Output Oracle Select

    本文转自:http://www.oraclealchemist.com/oracle/easy-stored-procedure-output/ I answered a question on a ...

随机推荐

  1. 【转】家庭wifi覆盖指导

    网址:家庭wifi覆盖指导 私以为,目前民用 wifi 路由器市场已经完全走上了邪路.天线越来越大,发射功率越做越高.都敢冒着法律的风险使用大大超过 100mW 的发射功率了.且不论巨大的发射功率可能 ...

  2. Spring Application Event Example

    Spring Application Event 项目结构 工程下载 https://github.com/xiaoheike/SpringApplicationEventExample.git Sp ...

  3. LoadRunner迭代与并发的理解

    ---恢复内容开始--- 四车道的马路,如果只有四辆车并排走过就是并发:  如果四辆车排成一纵队走过就是迭代:  如果有100辆车排成25行依次走过就是并发加迭代.  在以上说法中,只有并排的车是我们 ...

  4. oracle rman恢复数据库 方式恢复到异地数据库

    目的:从某个环境中,获取相关文件,放到异地机器使用rman 恢复.   情况说明:XX系统使用的是oracle数据库,现已从服务器拉下来相关文件,依靠这些文件来早本地的测试机上恢复数据库,方便进行数据 ...

  5. 关于a和b不用第三变量交换值的问题

    今天在如鹏网(不是发广告)上看到一道题,题目很难就不说了,但是老师给的提示的题目却让我感兴趣,就是标题的内容. 题目是把a与b做异或比较从而实现不通过第三变量来交换a和b的数值答案是这样的: a=a^ ...

  6. [NOIP2015] 子串(dp)

    题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问 ...

  7. 字符串hash算法

    http://www.cnblogs.com/zyf0163/p/4806951.html hash函数对大家来说不陌生吧 ? 而这次我们就用hash函数来实现字符串匹配. 首先我们会想一下二进制数. ...

  8. Chapter 5: Design and implement security

    Configure authentication Authenticating users IIS authentication Anonymous ASP.net impersonation Bas ...

  9. MYSQL file types redo log

    https://blogs.oracle.com/mysqlinnodb/entry/data_organization_in_innodb https://blogs.oracle.com/mysq ...

  10. Android应用开发-数据存储和界面展现(二)(重制版)

    SQLite数据库 // 自定义类MyOpenHelper继承自SQLiteOpenHelper MyOpenHelper oh = new MyOpenHelper(getContext(), &q ...