動態SQL開發基礎和經驗再總結

iSQlServer發表於2010-12-07

一、SQL語句直接處理非數字型列的“累加”問題

查詢要求:取出Person表中所有人的FirstName,並以逗號隔開。

可直接通過SELECT @local_variable = expression的形式實現:

 
1 DECLARE @Result varchar(8000)
2 SET @Result=''
3 SELECT @Result=@Result + CASE WHEN @Result='' THEN FirstName ELSE ',' + FirstName 
4 END FROM Person ORDER BY Id
5 SELECT @Result AS Names

我們還有一種比較笨拙的方式進行查詢,那就是通過遊標:

 
01 --使用遊標
02 DECLARE @Result varchar(8000)
03 DECLARE @SQL varchar(50)
04 DECLARE c CURSOR FORWARD_ONLY READ_ONLY FOR
05 SELECT FirstName FROM Person ORDER BY Id
06 SET @Result = ''
07 OPEN c
08 FETCH next FROM c INTO @SQL
09 WHILE @@fetch_status = 0
10 BEGIN
11    SET @Result = CASE WHEN @Result='' 
12    THEN @SQL 
13    ELSE @Result + ',' + @SQL 
14    END
15    FETCH next FROM c INTO @SQL
16 END
17 DEALLOCATE c
18 SELECT @Result AS Names

大部分SQL查詢我們都會力爭不用遊標,因為不用考慮分配和釋放遊標,可大大節省資料庫資源提升效率。

 

二、動態SQL語句基礎

在一中,我們已經使用了動態SQL。這裡再總結一下經常使用的動態SQL程式設計基礎。

1、單引號,雙引號

單引號:

 
1 SELECT '''' AS Result --單引號

那麼雙引號呢?8個單引號麼?如果是真的8個單引號一起,實際上返回的是3個單引號。真正的雙引號可以”含有“8個單引號,當然必須要像下面這樣加起來:

 
1 SELECT ''''+'''' AS Result --雙引號

但是更直接的寫法是下面這樣的:

 
1 SELECT '''''' AS Result --雙引號

沒錯,就是6個單引號連寫。

單引號和雙引號也可以搞得這麼煩?這也許正是SQL程式設計不如高階程式語言來得簡單直白的地方。

2、定義變數,給變數賦值

來看一個簡單的SQL語句:

 
1 DECLARE @a varchar(20),@b varchar(20)
2 SET @a='jeff' 
3 SET @b=' wong'
4 PRINT @a+@b

我們通過DECLARE定義變數,通過SET給變數賦值,也可以通過SELECT給變數賦值:

 
1 DECLARE @a varchar(20),@b varchar(20)
2 SELECT @a='jeff' 
3 SELECT @b=' wong'
4 PRINT @a+@b

SET和SELECT賦值的區別:據說SELECT 一次性賦值, 比用SET 逐個賦值效率好。

3、EXEC(@sql)

普通的SQL語句,可以直接通過EXEC執行

 
1 EXEC ('SELECT TOP 10 * FROM Person(NOLOCK) ORDER BY Id DESC')--兩邊的括號不可少

也可以通過定義變數,執行變數sql,但是必須加上括號:

 
1 DECLARE @Sql varchar(2000)
2 SET @Sql='SELECT TOP 10 * FROM Person(NOLOCK) ORDER BY Id DESC'
3 EXEC ( @Sql )

4、Exec sp_executesql

sp_executesql 支援對 Transact-SQL 字串中指定的任何引數的引數值進行替換,但是 EXECUTE 語句不支援。因此,由 sp_executesql 生成的 Transact-SQL 字串比由 EXECUTE 語句所生成的更相似。SQL Server 查詢優化器可能將來自 sp_executesql 的 Transact-SQL 語句與以前所執行的語句的執行計劃相匹配,以節約編譯新的執行計劃的開銷。

對於普通的SQL語句,這個和EXEC直接執行SQL是一樣的:

 
1 EXEC sp_executesql N'SELECT TOP 10 * FROM Person(NOLOCK) ORDER BY Id DESC' --必須加N

注意,那個大寫的N必須加在要執行的sql語句前面,而且那個N也不是白來的,它還有重要的含義!

如果我們執行的sql語句定義成變數的形式,下面的sql是無法執行的:

 
1 DECLARE @Sql varchar(2000)
2 SET @Sql='SELECT TOP 10 * FROM Person(NOLOCK) ORDER BY Id DESC'
3 EXEC sp_executesql @Sql

搞怪的是,如果將@sql變數型別由varchar改成nvarchar,就可以執行了:

 
1 DECLARE @Sql nvarchar(2000)
2 SET @Sql='SELECT TOP 10 * FROM Person(NOLOCK) ORDER BY Id DESC'
3 EXEC sp_executesql @Sql

到這裡哀樂響起,為什麼為什麼?偏偏你要折磨我?下面就來解惑吧:

(1)、EXEC sp_executesql N 這個倒貼過來的N表示後面的sql內容是unicode也是對應nvarchar型別;

(2)、將varchar改成nvarchar才能執行,就是為了執行sql時,將所有引數值轉換為字元或 unicode 並使其成為 Transact-SQL 字串的一部分。

5、將EXEC執行結果放入變數中

比如,我們需要查詢Person表的所有記錄數,可以像下面這樣實現將執行結果放入變數@Num中:

 
1 /*將exec執行結果放入變數num中*/
2 DECLARE @Num int, @Sql nvarchar(4000)  
3 SET @Sql='SELECT @TotalCount=COUNT(0) FROM Person '  
4 EXEC sp_executesql @Sql,N'@TotalCount int output',@Num output  
5 SELECT @Num AS TotalCount

6、兩個型別轉換函式

下面示例將整數(int)轉換成字串(varchar):

 
1 /*CASTConvert函式*/
2 DECLARE @input int
3 SET @input=1234
4 SELECT CONVERT(varchar(50),@input)+' abc' AS result
5 SET  @input=@input+1000
6 SELECT CAST(@input AS varchar(50))+ ' xyz' AS result

這兩個平時開發估計經常使用,大家應該不陌生。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16436858/viewspace-681072/,如需轉載,請註明出處,否則將追究法律責任。

相關文章