SQL Server之深入理解STUFF


前言

最近項目無論查詢報表還是其他數據都在和SQL Server數據庫打交道,對於STUFF也有了解,但是發現當下一次再寫SQL語句時我還得查看相關具體用法,說到底還是沒有完全理解其原理,所以本節我們來談談STUFF,Jeff是在項目中哪里不熟悉,哪里不會或者哪里耗時比較多就會去深入理解和鞏固即使是很基礎的知識,直到完全不用浪費時間去查閱相關資料,這是我的出發點。

深入理解STUFF

STUFF字符串函數是將字符串插入到另一個字符串中。它會刪除開始位置第一個字符串中的指定長度的字符,然后將第二個字符串插入到開始位置的第一個字符串中,語法如下。

STUFF(<character_expression>,<開始>,<長度>,<character_expression>)
<character_expression>參數是給定的字符串數據,可以是字符或二進制數據的常量,變量或列。<start>參數是一個整數值,指定開始刪除和插入的位置,可以是BIGINT類型。如果<開始>或<長度>參數為負數,則返回NULL字符串。如果<start>參數比第一個<character_expression>長,則返回一個NULL字符串。 <length>參數可以是BIGINT類型,它是一個整數,指定要刪除的字符數。如果<length>比第一個<character_expression>長,則刪除發生到最后一個<character_expression>中的最后一個字符。

DECLARE @FullName       VARCHAR(100)
DECLARE @Alias          VARCHAR(20)

SET @FullName = 'Jeffcky Wang'
SET @Alias = ' "Superman" '

SELECT STUFF(@FullName, CHARINDEX(' ', @FullName), 1, @Alias) AS [FullName]

 

如上STUFF函數中的第一個參數我們給定的是@FullName,第二個是開始的位置,我們通過CHARINDEX函數找出@FullName以空格隔開的的位置返回,最后由@Alias來代替,結果如圖所示。

DECLARE @Time VARCHAR(10)
SET @Time = '1030'

SELECT STUFF(@Time, 3, 0, ':') AS [HH:MM]

我們給定的字符串為@Time即1030,我們從第3個位置開始,刪除長度為0,此時則在3前面插入冒號,結果如上圖輸出10:30。

DECLARE @CreditCardNumber  VARCHAR(20)
SET @CreditCardNumber = '370200199408103544'

SELECT STUFF(@CreditCardNumber, LEN(@CreditCardNumber) -3, 4,
       'XXXX') AS [Output]

如上我們將身份證通過STUFF將最后四位用XXXX代替。以上是STUFF最基礎的用法。STUFF最常見的用途莫過於結合FOR XML PATH對返回JSON字符串的拼接。首先利用FOR XML PATH則返回XML格式的字符串,我們將FOR XML PATH添加到查詢的末尾,此時允許我們將查詢的結果作為XML元素輸出,元素名稱包含在PATH參數中。。

SELECT TOP 5 ',' + Name 
              FROM  Production.Product
              FOR XML PATH ('')

,Adjustable Race,All-Purpose Bike Stand,AWC Logo Cap,BB Ball Bearing,Bearing Ball

此時我們利用STUFF將上述利用FOR XML PATH生成的字符串中的前置逗號去掉,如下:

SELECT Name = STUFF((
            SELECT TOP 5 ',' + NAME
            FROM Production.Product
            FOR XML PATH('')
            ), 1, 1, '')

比如我們要查詢各種產品中的產品列表名稱,最后我們改造成如下:

SELECT TOP 5 p2.ProductID, Name = STUFF((
            SELECT ',' + NAME
            FROM Production.Product AS p1
            WHERE p1.ProductID = p2.ProductID
            FOR XML PATH('')
            ), 1, 1, '') FROM Production.Product AS p2
GROUP BY p2.ProductID

接下來我們利用STUFF結合FOR XML PATH來拼接JSON字符串,如下:

DECLARE @content VARCHAR(MAX)

SET @content = (SELECT '['+ STUFF((SELECT TOP 5 ',{"ProductName": "' + ProductName + '","Price": "' + CONVERT(VARCHAR, Price) + '","Quantity": "' + CONVERT(VARCHAR, quantity) + '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('')), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content

結果如上正確輸出JSON字符串,接下來我們將如上拼接換行再試試。

DECLARE @content VARCHAR(MAX)

SET @content = ( SELECT '['
                        + STUFF(( SELECT TOP 5
                                            ',{"ProductName": "' + ProductName
                                            + '","Price": "'
                                            + CONVERT(VARCHAR, Price)
                                            + '","Quantity": "'
                                            + CONVERT(VARCHAR, quantity)
                                            + '","Inserton": "'
                                            + CONVERT(VARCHAR, Inserton, 105)
                                            + '"}'
                                  FROM      ProductList
                                FOR
                                  XML PATH('')
                                ), 1, 1, '') + ']' [ProductDetail]
               )

PRINT @content

如上是利用SQL Prompt直接格式化換行,結果依然正確輸出JSON字符串,我們再來手動換行試試。

DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + ProductName 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) 
+ '"}' FROM ProductList 
 FOR XML PATH('')), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content

結果輸出如上我們不期望的字符串,主要是由FOR XML PATH造成的,比如我們利用FOR XML PATH進行如下查詢:

SELECT  '    '
FOR     XML PATH('') 

當我們利用FOR XML  PATH查詢數據時,如果字符串中包含空格時會造成出現以如上錯誤的字符串來填充,所以此時我們為了消除這種錯誤格式,我們將上述繼續添加參數。

SELECT  '    '
FOR     XML PATH(''),TYPE 

此時我們將上述輸出JSON字符串不錯誤的格式修改成如下即可:

DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + ProductName 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('') ,TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content

或者我們對上述輸出的錯誤字符串進行替換,如下:

select t.PK, 
    ltrim(rtrim(replace(
    (select ' ' + isnull(ti.Column1, '') + ' ' + isnull(ti.Column2, '')
     from yourTable ti 
     where ti.PK = t.PK
     for xml path (''))
     , '&#x20;', ''))) fruits
from yourTable t
group by t.PK;

這里我們解決了利用STUFF有可能輸出JSON字符串帶有錯誤的字符串的問題,在利用STUFF輸出JSON字符串時只要有一列數據包含NULL,那么返回的數據則為空,那么我們在對列數據通過ISNULL來進行判斷,比如如下將輸出NULL。

DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + NULL 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('') ,TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content

所以此時我們必須通過ISNULL來判斷列數據是否為NULL,修改成如下形式:

DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + ISNULL(ProductName,'') 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('') ,TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM