2013-10-17 56 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