2013-10-17 51 views
5

如何在SQL Server中模擬MySQL的CONCAT_WS()函數?CONCAT_WS()for SQL Server

此功能類似於CONCAT() function in SQL Server 2012但它增加了非NULL項之間的分隔符:

SELECT id, CONCAT_WS('; ', a, b, c, d) AS bar 
FROM foo 
ORDER BY id; 
| ID | BAR  | 
|----|------------| 
| 1 | a; b; c; d | 
| 2 | b; d  | 
| 3 | a; d  | 
| 4 |   | 

MySQL Fiddle

+0

我爲了回答這個問題我自己,使信息提供給任何人問過這個問題。 (對不起,如果已經有一個適當的問題,我找不到。)我會很樂意通過更好的提示upvote /接受其他答案。 –

回答

7

我們可以用幾個技巧:

  • 跳過NULL值:COALESCE()
  • 要避免尾隨分隔符:請在每個項目之前添加它,然後使用例如STUFF()

他是一個working example

CREATE TABLE foo (
    id INT IDENTITY(1, 1) NOT NULL, 
    a VARCHAR(50), 
    b VARCHAR(50), 
    c VARCHAR(50), 
    d VARCHAR(50), 
    PRIMARY KEY (id) 
); 

INSERT INTO foo (a, b, c, d) VALUES ('a', 'b', 'c', 'd'); 
INSERT INTO foo (a, b, c, d) VALUES (NULL, 'b', NULL, 'd'); 
INSERT INTO foo (a, b, c, d) VALUES ('a', NULL, NULL, 'd'); 
INSERT INTO foo (a, b, c, d) VALUES (NULL, NULL, NULL, NULL); 
SELECT id, 
STUFF(
    COALESCE('; ' + a, '') + 
    COALESCE('; ' + b, '') + 
    COALESCE('; ' + c, '') + 
    COALESCE('; ' + d, ''), 
1, 2, '') AS bar 
FROM foo 
ORDER BY id 
| ID | BAR  | 
|----|------------| 
| 1 | a; b; c; d | 
| 2 | b; d  | 
| 3 | a; d  | 
| 4 | (null)  | 

STUFF(..., 1, 2, '')的目的是去除初始分離器(2是在我們的情況下,分離器的長度)。

這應該適用於SQL Server 2005(以及可能更早的版本)。

注意:不像原來的CONCAT_WS(),我們的版本返回NULL當所有項目是NULL。我真的認爲這是一個更好的選擇,但無論如何它應該很容易改變。

5

另一種方法是將use a FOR XML subquery這樣的:

SELECT 
    id, 
    bar = STUFF(
    (
     SELECT '; ' + v 
     FROM (VALUES (a), (b), (c), (d)) AS v (v) 
     FOR XML PATH (''), TYPE 
    ).value('.[1]', 'varchar(max)'), 
    1, 2, '' 
) 
FROM foo 
ORDER BY id; 

,一方面,這看起來肯定要複雜得多了一系列COALESCE的要求。另一方面,這更接近於原型,因爲分隔符只被指定一次。

使用的語法至少需要SQL Server的2008+,但如果值構造改爲

SELECT a UNION ALL 
SELECT b UNION ALL 
SELECT c UNION ALL 
SELECT d 

查詢也將在SQL Server 2005運行

0

我用FOR XML做路徑。
您可以使用聯合(UNION ALL)而不是VALUES;這有附加價值,它仍然在SQL-Server 2005上工作(我們仍然需要在我們公司支持它),並且可以刪除NULL值。

DECLARE @in_SearchTerm1 nvarchar(100) 
DECLARE @in_SearchTerm2 nvarchar(100) 
DECLARE @in_SearchTerm3 nvarchar(100) 
DECLARE @in_SearchTerm4 nvarchar(100) 

SET @in_SearchTerm1 = N'a' 
SET @in_SearchTerm2 = N'' 
SET @in_SearchTerm3 = N'c' 
SET @in_SearchTerm4 = N'' 

SELECT 
    COALESCE 
    (
     STUFF 
     (
      (
       SELECT '/' + RPT_SearchTerm AS [text()] 
       FROM 
       (
            SELECT NULLIF(@in_SearchTerm1, N'') AS RPT_SearchTerm, 1 AS RPT_Sort 
         UNION ALL SELECT NULLIF(@in_SearchTerm2, N'') AS RPT_SearchTerm, 2 AS RPT_Sort 
         UNION ALL SELECT NULLIF(@in_SearchTerm3, N'') AS RPT_SearchTerm, 3 AS RPT_Sort 
         UNION ALL SELECT NULLIF(@in_SearchTerm4, N'') AS RPT_SearchTerm, 4 AS RPT_Sort 
       ) AS tempT 
       WHERE RPT_SearchTerm IS NOT NULL 
       ORDER BY RPT_Sort 
       FOR XML PATH(N''), TYPE 
      ).value('.', 'nvarchar(MAX)') 
      ,1 
      ,3 
      ,N'' 
     ) 
     ,N'' 
    ) AS RPT_SearchTerms 

請注意使用nvarchar - stop已經使用varchar。
您還必須訂購它,以保留序列。


那麼這是什麼呢:

目標:
拿在一份報告中4個獨立的過濾器inputed 4個搜索項。
在報告中連接'/'顯示這4個搜索條件。
如果搜索項爲空,則不應該有'// '
它應該按順序顯示,即term1/term2/term3/term4,而不是例如。 term4 /詞條2/TERM3 /字詞1。

如何:
因此,您將4個搜索條件放入一個聯合中,並添加一個排序值以保留順序。

您可以選擇從工會(separatur +空= NULL)

SELECT '/' + RPT_SearchTerm 
FROM (UNION OF SEARCH TEMRS) AS tempT 

通過RPT_Sort

定購

現在選擇在誘惑的所有值(分體+文字)到搜索項和分離器一個XML文件(FOR XML),其中所有的值都是XML元素與空標記名(PATH(N''),並選擇值XML文本(AS [text()])(又名element.innerXML)。

得到的,作爲XML的結果-ele換貨(TYPE)和檢索XML元素(.value('.', 'nvarchar(MAX)'))(又名XML解碼)的串的innerText。

最後,去掉開頭的 '/'(STUFF(var, 1,3, N'')

這在原則上是完全一樣的

CONCAT_WS('/', @in_SearchTerm1, @in_SearchTerm2, @in_SearchTerm3, @in_SearchTerm4) 

現在添加NULLIF,

CONCAT_WS('/', NULLIF(@in_SearchTerm1, '') , NULLIF(@in_SearchTerm2, ''), NULLIF(@in_SearchTerm3, ''), NULLIF(@in_SearchTerm4, '')) 

和你在那裏。

這就是你仍然能夠做到CONCAT_WS在SQL-服務器...

+0

這與Andriy M的回答有何不同? (對不起,我三年沒有看過這個東西,而且我也沒有全力以赴) –

+1

@ÁlvaroGonzález:我從谷歌登陸某個特定的答案。不幸的是沒有向上滾動,所以我沒有看到它。至於差異:是的,它使用nvarchar,這是更好的,因爲它實際上適用於所有語言)))它也使用NULLIF,這意味着空字符串被刪除(不只是空值)。這更有意義,恕我直言。對於不明白Andriy的UNION ALL含義的初學者來說,這可能會更好。所以我沒有刪除帖子。 –

+0

夠公平的。至於空字符串,我認爲整個概念是有缺陷的,他們應該從來沒有達到高級語言(我們沒有空的數字或空的日期,我們?),但因爲他們實際上在那裏我不認爲它是在技​​術上正確的將它們作爲NULL(即使Oracle),但這主要是一個意見問題,並且與問題本身沒有太大關係。 –

2

SQL服務器2017年(又名vNext)和CONCAT_WS將內置函數。

CONCAT_WS

把文本的可變數量的參數與所述第一參數指定的分隔符。 (CONCAT_WS指示與分離器串接。)NULL的

CONCAT_WS (separator, argument1, argument1 [, argumentN]…) 

處理值

CONCAT_WS忽略SET CONCAT_NULL_YIELDS_NULL {ON | OFF}設置。

如果所有的參數是空值,類型爲varchar的空字符串(1)是 返回。

在連接期間忽略空值,並且不會添加 分隔符。這有助於連接通常具有空值的字符串 的常見方案,例如第二個地址字段。 請參閱示例B.

如果您的方案要求將空值包含在分隔符中,請參閱使用ISNULL函數的示例C.

所以,你可以用你的初始查詢:

SELECT id, CONCAT_WS('; ', a, b, c, d) AS bar 
FROM foo 
ORDER BY id; 
0

我知道這是舊的文章,但我來了同樣的問題。

我簡單地使用CONCAT()函數。

我有保存在單個字段中的地址行,我想加入所有行來創建地址。

我發現CONCAT()函數可以處理NULL並用空字符串替換它。 如果有的話加NULL則爲NULL。

所以我用普通CONCAT()函數,並在每個地址行的末尾添加空間,所以如果該行是NULL,則聯合輸出爲null

SELECT 
    CONCAT(Address01 + ' ', Address02 + ' ', Address03 + ' ', Address04) AS Address 
FROM myTable 
+0

有趣......唯一的問題是,當「Address04」是「NULL」,並且至少以前的那個不是你會得到一個僞造的尾隨分隔符,不是嗎? –

+0

是的,但我們可以修剪它 –

1

對於SQL Server 2012可以簡化接受的答案用單CONCAT更換的COALESCE過多:

WITH tests(a, b, c, d) AS (
    SELECT NULL, NULL, NULL, NULL UNION 
    SELECT NULL, NULL, NULL, 'd' UNION 
    SELECT NULL, NULL, 'c', NULL UNION 
    SELECT NULL, NULL, 'c', 'd' UNION 
    SELECT NULL, 'b', NULL, NULL UNION 
    SELECT NULL, 'b', NULL, 'd' UNION 
    SELECT NULL, 'b', 'c', NULL UNION 
    SELECT NULL, 'b', 'c', 'd' UNION 
    SELECT 'a', NULL, NULL, NULL UNION 
    SELECT 'a', NULL, NULL, 'd' UNION 
    SELECT 'a', NULL, 'c', NULL UNION 
    SELECT 'a', NULL, 'c', 'd' UNION 
    SELECT 'a', 'b', NULL, NULL UNION 
    SELECT 'a', 'b', NULL, 'd' UNION 
    SELECT 'a', 'b', 'c', NULL UNION 
    SELECT 'a', 'b', 'c', 'd' 
) 
SELECT a, b, c, d, 
STUFF(CONCAT(
    '; ' + a, 
    '; ' + b, 
    '; ' + c, 
    '; ' + d 
), 1, 2, '') AS cat 
FROM tests 
a | b | c | d | cat 
-----+------+------+------+----------- 
NULL | NULL | NULL | NULL | NULL 
NULL | NULL | NULL | d | d 
NULL | NULL | c | NULL | c 
NULL | NULL | c | d | c; d 
NULL | b | NULL | NULL | b 
NULL | b | NULL | d | b; d 
NULL | b | c | NULL | b; c 
NULL | b | c | d | b; c; d 
a | NULL | NULL | NULL | a 
a | NULL | NULL | d | a; d 
a | NULL | c | NULL | a; c 
a | NULL | c | d | a; c; d 
a | b | NULL | NULL | a; b 
a | b | NULL | d | a; b; d 
a | b | c | NULL | a; b; c 
a | b | c | d | a; b; c; d