成人免费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-06-28 15:18:51

SQL Server

2010-11-08 17:07:41

SQL Server字

2010-09-03 11:35:50

2014-02-18 15:10:57

2021-01-19 05:39:17

SQLServer變量

2021-03-14 15:07:55

SQLServer數據庫字符串

2010-06-17 16:00:59

SQL Server

2020-03-02 16:41:06

戴爾

2013-06-24 15:16:29

Java字符串拼接

2010-09-13 15:06:40

sql server字

2011-07-11 16:00:22

字符串拼接

2021-05-31 07:57:00

拼接字符串Java

2010-09-13 14:55:09

sql server字

2010-07-09 09:54:34

SQL Server字
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区在线看 | 99精品国产一区二区三区 | 精品少妇v888av | 在线欧美一区 | 欧美精品网站 | 久久久精品日本 | 国产精品区一区二区三 | 久久久999国产精品 中文字幕在线精品 | 欧美无乱码久久久免费午夜一区 | 一区二区在线免费观看 | 毛片99 | 99爱免费| 国产亚洲精品成人av久久ww | 久久久久久国产精品免费 | 综合久久av | 台湾佬伊人 | 久久精品国产一区 | 超黄毛片| 在线观看视频91 | 武道仙尊动漫在线观看 | 国产精品久久久久久久7777 | 欧美性tv| 久久免费精品视频 | www.一区二区三区 | 国产分类视频 | 国户精品久久久久久久久久久不卡 | 国产精品久久久久免费 | 国产真实精品久久二三区 | 国产.com | 日本亚洲一区二区 | 亚洲一区二区三区免费在线 | 午夜久久 | 亚州精品天堂中文字幕 | 99久久精品一区二区成人 | 欧美一级片在线 | 国产ts人妖系列高潮 | 欧美精品一区二区三区在线 | 成人免费淫片aa视频免费 | 亚洲精品永久免费 | 国产一级片 | 91国在线视频 |