17

如何在 SQL Server 中模拟 MySQL 的CONCAT_WS()函数?

此函数类似于CONCAT()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小提琴

4

6 回答 6

21

我们可以使用几个技巧:

他是一个有效的例子

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。老实说,我认为这是一个更好的选择,但无论如何它应该很容易改变。

于 2013-10-17T16:33:38.963 回答
8

另一种方法是使用 FOR XML 子查询,如下所示:

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+,但如果将 VALUES 构造函数更改为

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

该查询也将在 SQL Server 2005 中运行。

于 2013-10-17T16:50:23.533 回答
6

SQL Server 2017开始,您可以使用内置CONCAT_WS

CONCAT_WS

将可变数量的参数与第一个参数中指定的分隔符连接起来。(CONCAT_WS 表示用分隔符连接。)

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

NULL 值的处理

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

如果所有参数都为 null,则返回 varchar(1) 类型的空字符串。

在连接过程中忽略空值,并且不添加分隔符。这有助于连接通常具有空白值的字符串的常见场景,例如第二个地址字段。参见示例 B。

如果您的方案需要在分隔符中包含空值,请参阅使用 ISNULL 函数的示例 C。

所以你可以使用你的初始查询:

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

db<>小提琴演示

于 2016-12-28T16:10:01.327 回答
5

对于 SQL Server 2012,您可以通过将 plethora of 替换为COALESCEsingle来简化接受的答案CONCAT

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
于 2017-12-20T12:03:20.800 回答
0

我用 FOR XML PATH 来做。
您可以使用联合 (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 的使用 - 已经停止使用 varchar。
您还必须订购它,以保持顺序。


那么这是做什么的:

目标:
获取报告中 4 个单独过滤器中输入的 4 个搜索词。
在由 连接的报告中显示这 4 个搜索词' / '。如果搜索词为空,
则不应有 a 。 它应该按顺序显示,即 term1/term2/term3/term4,而不是例如 term4/term2/term3/term1。' / / '

操作方法:
因此,您将 4 个搜索词合并,并添加一个排序值以保留 order 。

您从联合中选择搜索词和分隔符 (separatur + null = null)

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

按 RPT_Sort 排序

现在将 tempT 中的所有值(分隔符 + 文本)选择到一个 XML 文件 ( FOR XML) 中,其中所有值都是带有空标记名 ( ) 的 XML 元素PATH(N''),然后选择值 XML-text ( AS [text()])(又名 element.innerXML)。

将结果作为 XML-element ( TYPE) 获取并检索该 XML-element ( ) 的 innerText 字符串.value('.', 'nvarchar(MAX)')(又名 XML-decode)。

最后,去掉前面的 '/' ( 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, ''))

你就在那里。

这就是您仍然能够在 SQL-Server 中执行 CONCAT_WS 的方式...

于 2016-09-14T08:05:09.227 回答
0

我知道这是旧帖子,但我遇到了同样的问题。

我只是为此使用 CONCAT() 函数。

我在各个字段中保存了地址行,我想加入所有行来创建地址。

我发现 CONCAT() 函数可以处理 NULL 并将其替换为空字符串。如果任何东西加上 NULL 也是 NULL。

所以我使用常规的 CONCAT() 函数并在每个地址行的末尾添加空格,所以如果该行为 NULL,则组合输出为 null

SELECT 
    CONCAT(Address01 + ' ', Address02 + ' ', Address03 + ' ', Address04) AS Address 
FROM myTable
于 2017-08-20T03:12:33.453 回答