成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SQL Server解惑——為什么ORDER BY改變了變量的字符串拼接結果

運維 數據庫運維
簡單來說,這樣拼接字符串,雖然在語法上支持,但是卻不能保證這樣的結果正確性,聚合串聯查詢的行為是不確定的。

[[374304]]

本文轉載自微信公眾號「DBA閑思雜想錄」,作者瀟湘隱者。轉載本文請聯系DBA閑思雜想錄公眾號。   

在SQL Server中可能有這樣的拼接字符串需求,需要將查詢出來的一列拼接成字符串,如下案例所示,我們需要將AddressID <=10的AddressLine1字段拼接起來,分隔符為|。如下截圖所示。這種方式看起來似乎沒有什么問題,而且簡單測試也是OK的:

  1. USE AdventureWorks2014; 
  2. GO 
  3. DECLARE @address_list NVARCHAR(MAX); 
  4. SET @address_list =''
  5.  
  6. SELECT @address_list = @address_list + AddressLine1 + '|'  
  7. FROM [Person].[Address] WHERE AddressID <=10; 
  8.  
  9. SELECT @address_list 

但是,如果SQL多了一個排序操作,結果就變了,這個SQL的變量@address_list只獲取到了最后一條記錄”9833 Mt. Dias Blv.|“,

  1. USE AdventureWorks2014; 
  2. GO 
  3. DECLARE @address_list NVARCHAR(MAX); 
  4. SET @address_list =''
  5.  
  6. SELECT @address_list = @address_list + AddressLine1 + '|'  
  7. FROM [Person].[Address] WHERE AddressID <=10 ORDER BY 1; 
  8.  
  9. SELECT @address_list 

但是你使用其它一些字段排序的話,它又是OK的。在各種實際生產環境中,可能按某個字段排序,字符串拼接就不正常了。但是按有些字段排序又是正常的。有點搞不清套路。下面簡單構造一個案例

  1. USE AdventureWorks2014; 
  2. GO 
  3. CREATE TABLE TEST 
  4.     ID  INT NOT NULL 
  5.    ,NAME NVARCHAR(100) NOT NULL  
  6.    ,SortID  INT NOT NULL 
  7.    ,CONSTRAINT PK_TEST PRIMARY KEY (ID) 
  8. ); 
  9.  
  10. INSERT INTO dbo.TEST 
  11. SELECT 1, 'Kerry'  , 1 UNION ALL  
  12. SELECT 2, 'Jerry'  , 2 UNION ALL 
  13. SELECT 3, 'Ken'    , 3 UNION ALL 
  14. SELECT 4, 'Richard', 4 UNION ALL 
  15. SELECT 5, 'Jimmy'  , 5; 
  16.  
  17. DECLARE @name_list NVARCHAR(100); 
  18. SET @name_list=''
  19.  
  20. SELECT @name_list = @name_list + t.NAME + '|' 
  21. FROM dbo.TEST t 
  22. ORDER BY t.SortID; 
  23.  
  24. SELECT @name_list; 

上面腳本測試都正常,下面測試就會出現連接字符串只獲取了最后一行記錄的情況。

  1. DECLARE @name_list NVARCHAR(100)=''
  2.  
  3. SET @name_list=' ' 
  4. SELECT @name_list = @name_list + t.NAME + '| ' 
  5. FROM dbo.TEST t 
  6. WHERE ID IN (1,2,3) 
  7. ORDER BY t.SortID; 
  8.  
  9. SELECT @name_list; 

在生產環境還有各種魔幻的現象,按其中一個字段排序是正常,換另外一個字段排序就出現這種現象。如果你將上面測試表的字段的大小修改一下,然后測試下面腳本,發現又不會出現這種情況:

  1. USE AdventureWorks2014; 
  2. GO 
  3. DROP TABLE dbo.TEST; 
  4. GO 
  5. CREATE TABLE TEST 
  6.  ID  INT NOT NULL 
  7.    ,NAME NVARCHAR(32) NOT NULL  
  8.    ,SortID  INT NOT NULL 
  9.    ,CONSTRAINT PK_TEST PRIMARY KEY (ID) 
  10. ); 
  11.  
  12. INSERT INTO dbo.TEST 
  13. SELECT 1, 'Kerry'  , 1 UNION ALL  
  14. SELECT 2, 'Jerry'  , 2 UNION ALL 
  15. SELECT 3, 'Ken'    , 3 UNION ALL 
  16. SELECT 4, 'Richard', 4 UNION ALL 
  17. SELECT 5, 'Jimmy'  , 5; 

初看像一個“Bug”,但是它確實不是一個Bug,官方文檔http://support.microsoft.com/kb/287515有介紹這個現象,但是目前現在這個鏈接失效了,搜索也找不到對應的鏈接了(微軟的官方文檔這一點是相當坑爹,不如Oracle做得好,經常一個鏈接失效,好的情況是鏈接換了,糟糕的情況就是這種,根本找不到了),下面的資料是在其它資料里面引用KB 287515的內容:

事實證明,此迭代級聯/迭代拼接(iterative concatenation)的功能是不受支持的功能。Microsoft知識庫文章287515指出

You may encounter unexpected results when you apply any operators or expressions to the ORDER BY clause of aggregate concatenation queries.

We do not make any guarantees on the correctness of concatenation queries (like using variable assignments with data retrieval in a specific order). The query output can change in SQL Server 2008 depending on the plan choice, data in the tables etc. You shouldn't rely on this working consistently even though the syntax allows you to write a SELECT statement that mixes ordered rows retrieval with variable assignment.

The correct behavior for an aggregate concatenation query is undefined

簡單來說,這樣拼接字符串,雖然在語法上支持,但是卻不能保證這樣的結果正確性,聚合串聯查詢的行為是不確定的。如果想安全可靠的拼接字符串的話,有下面一些方式:

  1. 使用游標循環循環處理拼接字符串。
  2. 使用XML查詢拼接字符串

方式1:

  1. DECLARE @name_list VARCHAR(512); 
  2.  
  3. SELECT  @name_list= 
  4. SELECT  t.NAME + '|' 
  5. FROM dbo.TEST t 
  6. WHERE ID IN (1,2,3) 
  7. ORDER BY t.SortID 
  8. FOR XML PATH(''), TYPE 
  9. ).value('.''varchar(max)'
  10.  
  11. SELECT @name_list; 

方式2:

  1. SELECT Name + '|' AS 'data()'  
  2. FROM dbo.TEST  
  3. WHERE ID IN (1,2,3) 
  4. FOR XML PATH(''); 

方式3. 借助STUFF函數

方式4. 借助COALESCE函數

注意,使用COALESCE有可能也是不行的。如果定義@name_list為 VARCHAR(512)或VARCHAR(MAX)則是OK的。

  1. DECLARE @name_list VARCHAR(100); 
  2. SELECT @name_list = COALESCE(@name_list + ', ''') + Name  
  3. FROM dbo.TEST 
  4. WHERE ID IN (1,2,3) 
  5. ORDER BY SortID 
  6.  
  7. SELECT @name_list 

5. 使用CRL聚合拼接字符串。

6. 如果SQL Server 2017使用STRING_AGG實現。

  1. SELECT  STRING_AGG(Name'|'AS Departments 
  2. FROM dbo.TEST 
  3. WHERE ID IN (1,2,3) 
  4.  
  5.  
  6. SELECT SortID, STRING_AGG(Name'|'AS Departments 
  7. FROM dbo.TEST 
  8. WHERE ID IN (1,2,3) 
  9. GROUP BY SortID 
  10. ORDER BY SortID; 

參考資料:

https://stackoverflow.com/questions/5538187/why-sql-server-ignores-vaules-in-string-concatenation-when-order-by-clause-speci/5538210#5538210

https://stackoverflow.com/questions/194852/how-to-concatenate-text-from-multiple-rows-into-a-single-text-string-in-sql-serv

 

責任編輯:武曉燕 來源: DBA閑思雜想錄
相關推薦

2021-12-14 07:05:00

SQL語句數據庫

2025-02-27 08:18:40

2010-09-13 15:12:26

sql server字

2016-12-27 09:46:55

Java 8StringBuild

2017-01-19 11:26:55

Java 8StringBuild

2021-01-05 14:44:39

比特幣加密貨幣黃金

2010-11-08 17:07:41

SQL Server字

2010-06-28 15:18:51

SQL Server

2014-02-18 15:10:57

2010-09-03 11:35:50

2021-03-14 15:07:55

SQLServer數據庫字符串

2010-06-17 16:00:59

SQL Server

2021-01-19 05:39:17

SQLServer變量

2020-03-02 16:41:06

戴爾

2010-09-13 15:06:40

sql server字

2011-07-11 16:00:22

字符串拼接

2013-06-24 15:16:29

Java字符串拼接

2010-07-09 09:54:34

SQL Server字

2021-02-03 08:01:35

SQLServerLIKE

2023-01-03 08:07:33

Go字符串指針
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美综合在线视频 | 日本久久精品视频 | 亚洲导航深夜福利涩涩屋 | 国产在线播放一区二区三区 | 亚洲日韩中文字幕一区 | 在线āv视频 | 在线免费观看a级片 | 久久亚洲天堂 | 色综合一区二区 | 久久久久久久久国产成人免费 | 日本三级网站在线观看 | 精品一区二区三区日本 | 在线观看免费av网站 | 色综合久久88色综合天天 | 精品一区二区三区四区外站 | 亚洲九九| 免费观看黄色片视频 | 北条麻妃99精品青青久久主播 | 国产精品久久久久久久久久免费看 | 国产欧美一区二区三区久久 | 丁香婷婷在线视频 | 99re超碰| 久久在线免费 | av第一页 | 欧美日韩国产一区二区 | 国产福利91精品一区二区三区 | 九色国产 | 久久草在线视频 | 国产一二区视频 | 99久久免费观看 | 国产999精品久久久影片官网 | 中国xxxx性xxxx产国 | 成人h动漫亚洲一区二区 | 成人在线精品 | 久久综合一区 | 丝袜美腿一区二区三区动态图 | 久久精品无码一区二区三区 | 成人在线国产 | 久草网址| 免费激情av | 欧美国产精品久久久 |