動態sql語句基本語法--Exec與Exec sp_executesql 的區別

http://www.cnblogs.com/goody9807/archive/2010/10/19/1855697.htmlhtml

 

動態sql語句基本語法  sql

1   :普通SQL語句能夠用Exec執行  
eg:       Select   *   from   tableName                     數據庫

Exec( 'select   *   from   tableName ')                     緩存

Exec   sp_executesql   N 'select   *   from   tableName '         --   請注意字符串前必定要加N   安全


2:字段名,表名,數據庫名之類做爲變量時,必須用動態SQL  
eg:       函數

declare   @fname   varchar(20)   set   @fname   =   'FiledName '   post

Select   @fname   from   tableName          --   錯誤,不會提示錯誤,但結果爲固定值FiledName,並不是所要。   性能

Exec( 'select   '   +   @fname   +   '   from   tableName ')           --   請注意   加號先後的   單引號的邊上加空格  
固然將字符串改爲變量的形式也可   url

declare   @fname   varchar(20)   set   @fname   =   'FiledName '   --設置字段名  
declare   @s   varchar(1000)   set   @s   =   'select   '   +   @fname   +   '   from   tableName '   Exec(@s)            --   成功   spa

exec   sp_executesql   @s       --   此句會報錯  
declare   @s   Nvarchar(1000)     --   注意此處改成nvarchar(1000)  

set   @s   =   'select   '   +   @fname   +   '   from   tableName '  

Exec(@s)                                 --   成功          

exec   sp_executesql   @s       --   此句正確  


3.   輸出參數  

declare   @num   int,   @sql   nvarchar(4000)  

set   @sql= 'select   count(*)   from   tableName '  

exec(@sql)  
--如何將exec執行結果放入變量中?  
declare   @num   int,   @sql   nvarchar(4000)  

set   @sql= 'select   @a=count(*)   from   tableName   '  

exec   sp_executesql   @sql,N '@a   int   output ',@num   output   select   @num  

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

@maxnum  int  output --最大數量 

declare @idcount int --用於存儲 exec 語句賦值的變量

declare @maxpagesql  nvarchar(300)  --必定要nvarchaar

set @maxpagesql = 'select  @idcount=count(id) from QuestionInfo where 1=1 ' 

exec  sp_executesql  @maxpagesql,N'@idcount   int   output ',@maxnum   output 

select @maxnum

 

動態SQL EXEC(http://www.cnblogs.com/Junelee1211/archive/2011/08/25/2153024.html)

一、EXEC命令的括號中只容許包含一個字符串變量,或者一個 字符串文本,或者字符串變量與字符串文本的串聯。不能再括號中使用函數或CASE表達式,以下面嘗試在括號中調用QUOTENAME函數以引用對象名稱,運行將失敗:

 

   1:  DECLARE @schemaname NVARCHAR(255),@tablename NVARCHAR(128)
   2:  SET @schemaname='dbo'
   3:  SET @tablename='Order Details'
   4:   
   5:  EXEC (N'SELECT COUNT(*) FROM '+QUOTENAME(@schemaname)+N'.'+QUOTENAME(@tablename)+N';')

上述代碼將會產生以下錯誤:

消息 102,級別 15,狀態 1,第 5 行    'QUOTENAME' 附近有語法錯誤。    SQL Server 分析和編譯時間:       CPU 時間 = 0 毫秒,佔用時間 = 0 毫秒。

SQL Server 執行時間:       CPU 時間 = 0 毫秒,佔用時間 = 0 毫秒。   

因此作好的方法是把代碼構造到一個變量中,這樣就不會受限制了,而後再把該變量做爲EXEC命令的輸入參數,就像這樣:

   1:  DECLARE @schemaname NVARCHAR(255) ,
   2:      @tablename NVARCHAR(128) ,
   3:      @sql NVARCHAR(MAX)
   4:  SET @schemaname = 'dbo'
   5:  SET @tablename = 'Order Details'
   6:  SET @sql = N'SELECT COUNT(*) FROM ' + QUOTENAME(@schemaname) + N'.'
   7:      + QUOTENAME(@tablename) + N';'
   8:  EXEC (@sql)

 

二、EXEC不提供接口。EXEC(<string>)不提供接口。它惟一的輸入就是包含你要調用代碼的字符串。動態批處理不能訪問在調用批處理中定義的局部變量。以下面代碼嘗試訪問定義在調用批處理中的變量將失敗。

   1:  DECLARE @i INT 
   2:  SET @i = 10248
   3:   
   4:  DECLARE @sql NVARCHAR(MAX)
   5:   
   6:  SET @sql = 'SELECT * FROM dbo.Orders WHERE OrderID=@i;'
   7:  EXEC(@sql)

將產生以下錯誤:

消息 137,級別 15,狀態 2,第 1 行    必須聲明標量變量 "@i"。

 

使用EXEC時,若是想訪問變量,必須把變量內容串聯到動態構建的 代碼字符串中。

DECLARE @i INT SET @i = 10248 DECLARE @sql NVARCHAR(MAX) SET @sql = 'SELECT * FROM dbo.Orders WHERE OrderID=' + CAST(@i AS NVARCHAR(10)) + ';' EXEC(@sql)

這樣就沒有問題了。

 

若是一個變量包含字符串,把該變量的內容串聯到代碼將會致使安全風險(SQL注入),爲了不SQL注入,能夠吧字符串大小限制爲所需的最小長度。固然,實際中這種狀況根本不須要動態SQL直接執行SQL語句就能夠,這個示例只是爲了演示。

 

串聯變量的內容存在性能方面的弊端,SQL Server將爲每一個惟一的查詢字符串建立新的即席執行計劃,即便查詢模式相同也是這樣的。爲演示這一點,先清空緩存中的執行計劃。

DBCC FREEPROCCACHE
將上端代碼執行三次,分別爲@i賦值10248,10249和10250,而後使用下面的代碼查詢   
   1:  SELECT cacheobjtype ,
   2:          objtype ,
   3:          usecounts ,
   4:          sql
   5:  FROM sys.syscacheobjects
   6:  WHERE sql NOT LIKE '%cache%'
   7:          AND sql NOT LIKE '%sys.%'

獲得查詢結果:

 

cacheobjtype    objtype    usecounts    sql    Compiled Plan    Adhoc    1    SELECT * FROM dbo.Orders WHERE OrderID=10250;    Compiled Plan    Adhoc    1    SELECT * FROM dbo.Orders WHERE OrderID=10248;    Compiled Plan    Prepared    3    (@1 smallint)SELECT * FROM [dbo].[Orders] WHERE [OrderID]=@1    Compiled Plan    Adhoc    4    SET STATISTICS IO ON SET STATISTICS TIME ON    Compiled Plan    Adhoc    1    SELECT * FROM dbo.Orders WHERE OrderID=10249;    Compiled Plan    Adhoc    4    SET STATISTICS IO OFF SET STATISTICS TIME OFF

 

EXEC除了不支持動態批處理中的輸入參數外,也不支持輸出參數。默認狀況下,EXEC把查詢輸出返回給調用者。若是你想把輸出結果返回給調用批處理中的變量,事情就沒那麼簡單了,爲此,你須要使用INSERT EXEC把輸出插入到一個目的表,而後再從該表中取值,賦給該變量,就像這樣:

 

   1:  DECLARE @schemaname NVARCHAR(128) ,
   2:      @tablename NVARCHAR(128) ,
   3:      @colname NVARCHAR(128) ,
   4:      @sql NVARCHAR(MAX) ,
   5:      @cnt INT
   6:      
   7:  SET @schemaname = 'dbo'
   8:  SET @tablename = 'Orders'
   9:  SET @colname = 'CustomerID'
  10:       
  11:  SET @sql = N'SELECT COUNT(DISTINCT ' + QUOTENAME(@colname) + ') FROM '
  12:      + QUOTENAME(@schemaname) + N'.' + QUOTENAME(@tablename) + N';'
  13:      
  14:  CREATE TABLE #T1 ( cnt INT )
  15:  INSERT  INTO #T1
  16:          EXEC ( @sql
  17:              )
  18:  SELECT @cnt = cnt
  19:  FROM #T1
  20:  SELECT @cnt
  21:  DROP TABLE #T1

三、在SQL Server2000中串聯變量值時,EXEC比sp_executesql多一個優點,它支持更長的代碼,儘管技術上sp_executesql的輸入代碼字符串是NTEXT類型的,但你通常是在局部變量中構造代碼字符串。而你又不能用大型對象類型聲明局部變量,因此,實際上在sp_executesql中執行的查詢字符串被限制爲Unicode字符串(NVARCHAR)支持的最大長度4000,而EXEC支持常規字符串(VARCHAR)容許最大8000個字符。另外EXEC還支持一個特殊的功能,它容許你在括號中串聯多個變量,每一個變量都支持8000個字符的長度。

在SQL Server2005中,就不用這麼糾結了,由於能夠爲EXEC命令提供一個VARCHAR(MAX)或NVARCHAR(MAX)的變量做爲輸入,輸入字符串能夠達到2GB大小

相關文章
相關標籤/搜索