1. 程式人生 > >SQL Server解惑——為什麼ORDER BY改變了變數的字串拼接結果

SQL Server解惑——為什麼ORDER BY改變了變數的字串拼接結果

 

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

 

USE AdventureWorks2014;
GO
DECLARE @address_list NVARCHAR(MAX);
SET @address_list ='';
 
SELECT @address_list = @address_list + AddressLine1 + '|' FROM [Person].[Address] WHERE AddressID <=10;
 
SELECT @address_list

 

 

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

 

USE AdventureWorks2014;
GO
DECLARE @address_list NVARCHAR(MAX);
SET @address_list ='';
 
SELECT @address_list = @address_list + AddressLine1 + '|' FROM [Person].[Address] WHERE AddressID <=10 ORDER BY 1;
 
SELECT @address_list

 

 

 

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

 

USE AdventureWorks2014;
GO
CREATE TABLE TEST
(
    ID        INT NOT NULL
   ,NAME    NVARCHAR(100) NOT NULL 
   ,SortID  INT NOT NULL
   ,CONSTRAINT PK_TEST PRIMARY KEY (ID)
);
 
INSERT INTO dbo.TEST
SELECT 1, 'Kerry'  , 1 UNION ALL 
SELECT 2, 'Jerry'  , 2 UNION ALL
SELECT 3, 'Ken'    , 3 UNION ALL
SELECT 4, 'Richard', 4 UNION ALL
SELECT 5, 'Jimmy'  , 5;
 
DECLARE @name_list NVARCHAR(100);
SET @name_list='';
 
SELECT @name_list = @name_list + t.NAME + '|'
FROM dbo.TEST t
ORDER BY t.SortID;
 
SELECT @name_list;
 

 

 

上面指令碼測試都正常,下面測試就會出現連線字串只獲取了最後一行記錄的情況。

 

 

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

 

 

 

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

 

USE AdventureWorks2014;
GO
DROP TABLE dbo.TEST;
GO
CREATE TABLE TEST
(
    ID         INT NOT NULL
   ,NAME       NVARCHAR(32) NOT NULL 
   ,SortID     INT NOT NULL
   ,CONSTRAINT PK_TEST PRIMARY KEY (ID)
);
 
INSERT INTO dbo.TEST
SELECT 1, 'Kerry'  , 1 UNION ALL 
SELECT 2, 'Jerry'  , 2 UNION ALL
SELECT 3, 'Ken'    , 3 UNION ALL
SELECT 4, 'Richard', 4 UNION ALL
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:

 

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

 

方式2:

 

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

 

方式3: 藉助STUFF函式

 

   方式4: 藉助COALESCE函式

 

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

 

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

 

 

 

5: 使用CRL聚合拼接字串。

 

 

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

 

 
SELECT  STRING_AGG(Name, '|') AS Departments
FROM dbo.TEST
WHERE ID IN (1,2,3)
 
 
SELECT SortID, STRING_AGG(Name, '|') AS Departments
FROM dbo.TEST
WHERE ID IN (1,2,3)
GROUP BY SortID
            
           

相關推薦

SQL Server解惑&mdash;&mdash;為什麼ORDER BY改變變數字串拼接結果

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

SQL SERVER 子查詢使用Order By;按In排序

【子查詢】使用order by select * from (select top 100 percent * from table order by id) a 這是發現結果沒有按id排序,需要將100 percent 改成 99.999 percent 或10000000(儘量大)

SQL Server解惑&mdash;&mdash;標識列的限制和跳號現象

  1:每個表只能建立一個標識列。   如下測試所示,如果表中有一個標識列,新增一個標識列就會遇到錯誤“Multiple identity columns specified for table 'TEST'. Only one identity column per table is a

SQL Server解惑&mdash;&mdash;查詢條件IN中能否使用變數

在SQL Server的查詢條件中,能否在IN裡面使用變數呢? 如果可以的話,有沒有需要注意的地方或一些限制呢?在回答這個問題前,我們先來看看這個例子:   IF EXISTS (SELECT 1 FROM sys.objects WHERE name='TEST' AND t

[翻譯]SQL Server等待事件&mdash;THREADPOOL

完全 ava 吃飯 onf 嘗試 mapping pan 因此 ble 原文:[翻譯]SQL Server等待事件—THREADPOOL 前言: 本文是對SQLSkills上一篇關於SQL Server中THREADPOOL等待的博客的翻譯,本文也不是

sql 大數據查詢慎用 order by

images 一個 com style count code 今天 not img 今天在sql 查詢中一個表中查詢花了至少20秒時間,數據為620000行,sql語句如下: 測試一:使用order by 單單只是查詢0,10行數據,耗時27.888s select a.

Microsoft SQL Server 2008 Analysis Services Step by Step 學習

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

SQL語句,IN 和ORDER BY搭配使用的結果

工作過程中遇到的一個現象,覺得很神奇,記錄一下 不多說,直接上SQL語句 SELECT * FROM `industry_sector` where industry_id IN (11,4,6) ORDER BY industry_id asc 原本我以為出現的結果會

sql分組排序(union order by排序問題)

在實際的查詢過程中我們時常會有這樣的需求:某一類資料很重要要排在前面,其他資料排在後面,預設安裝建立時間或者其他欄位進行排序,這時候最好的辦法就是用union 將查詢到的兩個資料集進行組合排序,新增一個偽列對分組進行組外排序,sql如下: select * from( SELECT *,1 as

SQL】兩個帶order by查詢進行union all報ORA-00933錯誤的解決方法

在oracle SQL中,要求order by是select語句的最後一個語句,而且一個select語句中只允許出現一個order by語句,而且order by必須位於整個select語句的最後。 當時是要將一個十分複雜的檢索明細查詢和一個十分複雜的檢索彙總查詢的結果

SQL 檢索排序資料(ORDER BY子句)

ORDER BY 子句用於對結果集按照一個列或者多個列進行排序。 ORDER BY 子句預設按照升序對記錄進行排序。如果需要按照降序對記錄進行排序,您可以使用 DESC 關鍵字。 注意:ORDER BY 子句應該位於FROM子句之後,若使用LIMIT關鍵字時,LIMIT關

《Microsoft SQL Server 2008 Analysis Services Step by Step》學習筆記一:入門

導讀:本文主要介紹了建立SQL Server Analysis Service專案及資料來源、資料來源檢視的基本過程。  (一)BI基礎概念 一個BI(Business intelligence)系統最多可以有五層: 1. A data source layer(資料來

《Microsoft SQL Server 2008 Analysis Services Step by Step》學習筆記八:使用帳戶智慧(上)

導讀:本文介紹如何使用賬戶智慧(Account Intelligence) 本文末尾提供兩個專案原始碼:AdventureWorks_BI_Begin5和AdventureWorks_BI_End5,顧名思義,開始和完成。另外,包括資料庫檔案SSAS2008SBS_Da

sql語句之多個ORDER BY

一.ORDER BY語句 Ⅰ.DESC逆序 ORDER BY 語句用於根據指定的列對結果集進行排序。 ORDER BY 語句預設按照升序對記錄進行排序。 如果您希望按照降序對記錄進行排序,可以使用 DESC 關鍵字。 以逆字母順序顯示公司名稱: SELEC

sql語句中order by指定多個欄位,則怎麼排序?

舉個例子吧:order by id desc,time desc先是按 id 降序排列 (優先)如果 id 欄位 有些是一樣的話 再按time 降序排列 (前提是滿足id降序排列)  order by name, age desc  name優先name一樣的話 就按a

LINQ體驗(6)——LINQ to SQL語句之Join和Order By

Join操作 適用場景:在我們表關係中有一對一關係,一對多關係,多對多關係等。對各個表之間的關係,就用這些實現對多個表的操作。 說明:在Join操作中,分別為Join(Join查詢), SelectMany(Select一對多選擇)和GroupJoin(分組Join查詢)。該

SQL基本函式學習筆記(order by decode)

四、LPAD與RPAD的用法: 比較:select LPAD('WhaT is tHis',5),LPAD('WhaT is tHis',25),LPAD('WhaT is tHis',25,'-') from dual;             |WhaT|               WhaT is tH

《Microsoft SQL Server 2008 Analysis Services Step by Step》學習筆記十八:管理部署

導讀:本文介紹Analysis Services的部署方式和部署機制 。 本文將包括以下內容: ■1、使用BIDS部署Anylysis services 資料庫 ■2、建立XMLA指令碼部署Anylysis services 資料庫 ■3、針對Anylysis services 資料庫伺服器上執行部署

[SQL]sql server中如何直接查詢存儲過程EXEC返回的結果集?

arc div lec rom 結果 In varchar SQ type Declare @T Table (iDay VARCHAR(4),iNum DECIMAL(18,2),yuxiang DECIMAL(18,9))

SQL SERVER-3-order by|型別轉換與日期格式|聯合union

 1.order by --order by在sql語句中位置一定是在最後。。 --select ....3>對篩選出的資料再進行列的篩選,select是對列的篩選 --from ....  1> 從資料來源中獲取資料 --where .....2> 從獲