[转]Dynamic SQL & Stored Procedure Usage in T-SQL
转自: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 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
*/ -- 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 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
------------ -- 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的更多相关文章
- 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 ...
- SQL Stored Procedure and Function
Anything can be programmable with defined syntax and common lib. )) -- Add the parameters for the st ...
- SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases)
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems) 实现代码(SQL Codes) 方法一:拼接SQL: 方法二: ...
- SQL Server——存储过程(Stored Procedure)、事物、触发器
存储过程(proc 或 procedure) 存储过程(Stored Procedure),计算机用语,是一组为了完成特定功能的SQL语句集,是利用SQL Server所提供的Transact-SQL ...
- java当中JDBC当中请给出一个sql server的stored procedure例子
3.sql server的stored procedure例子: import java.sql.*;public class StoredProc0 {public static void main ...
- 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 ...
- Stored Procedure 里的 WITH RECOMPILE 到底是干麻的?
在 SQL Server 创建或修改「存储过程(stored procedure)」时,可加上 WITH RECOMPILE 选项,但多数文档或书籍都写得语焉不详,或只解释为「每次执行此存储过程时,都 ...
- 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 (不写邀请码,没有现金送) 国 ...
- [转]Easy Stored Procedure Output Oracle Select
本文转自:http://www.oraclealchemist.com/oracle/easy-stored-procedure-output/ I answered a question on a ...
随机推荐
- Node.js高效按行输出文件内容
const fs = require('fs'); const EventEmitter = require('events'); const util = require('util'); cons ...
- SOJ 1717 Computer (单机任务调度)
一.题目描述 Constraints :Time Limit: 2 secs, Memory Limit: 32 MB Description: We often hear that computer ...
- JAVA,NET RSA密钥格式转换
JAVA和NET RSA密钥格式相互转换(公钥,私钥) 做了一个小项目遇到java和.net非对称加密问题,java的公钥和私钥就直接是一个字符串的形式展示的,但是.net是以xml简单包裹形式展示的 ...
- 最小生成树——kruskal算法
kruskal和prim都是解决最小生成树问题,都是选取最小边,但kruskal是通过对所有边按从小到大的顺序排过一次序之后,配合并查集实现的.我们取出一条边,判断如果它的始点和终点属于同一棵树,那么 ...
- iOS测试常见崩溃
什么是崩溃日志,从哪里能得它? iOS设备上的应用闪退时,操作系统会生成一个崩溃报告,也叫崩溃日志,保存在设备上.崩溃日志上有很多有用的信息,包括应用是什么情况下闪退的.通常,上面有每个正在执行线程的 ...
- 《C与指针》第十一章练习
本章问题 1.在你的系统中,你能够声明的静态数组最大的长度能达到多少?使用动态内存分配,你最大能获取的内存块有多少? answer: This will vary from system to sys ...
- hiho一下21周 线段树的区间修改 离散化
离散化 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~ 这天小Hi和小Ho ...
- [NOIP2011] 观光公交(贪心)
题目描述 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第 0 分钟出现在 1号景点,随后依次前往 2 ...
- 如何用java写出无副作用的代码
搞java的同学们可能对无副作用这个概念比较陌生,这是函数式编程中的一个概念,无副作用的意思就是: 一个函数(java里是方法)的多次调用中,只要输入参数的值相同,输出结果的值也必然相同,并且在这个函 ...
- VS2008基于对话框的MFC上位机串口通信(C++实现)简单例程
首先,在 vs2008 环境下创建 MFC 运用程序 设置项目名称为 ComTest(这个地方随意命名,根据个人习惯),点击确定后,点击下一步 出现如下界面 选择"基于对话框"模式 ...