SQL Server将选择的列转换为字符串

35

有没有可能编写一个语句,从表中选择一列并将结果转换为字符串?

理想情况下,我希望得到逗号分隔的值。

例如,假设SELECT语句看起来像:

SELECT column
FROM table
WHERE column<10

结果是一个具有数值的列

|column|
--------
|  1   |
|  3   |
|  5   |
|  9   |
我希望作为结果得到字符串"1, 3, 5, 9"。

1
你想要在SQL中返回结果还是可以在代码中完成,比如在Winform上? - lemunk
1
完全复制了Merge row values into a CSV (a.k.a GROUP_CONCAT for SQL Server)。还有很多其他的。 - gbn
1
我需要在SQL中得到结果(因为我想将其作为更大的结果表的列值使用)。 - eddy ed
12个回答

75
你可以这样做:

Fiddle演示


请注意,保留了HTML标签。
declare @results varchar(500)

select @results = coalesce(@results + ',', '') +  convert(varchar(12),col)
from t
order by col

select @results as results

| RESULTS |
-----------
| 1,3,5,9 |

4
这个方法没有文档说明它能够正确工作,并且经常出现问题。从Connect网站上的各种引用可以看到,如下所示:https://dev59.com/aGUp5IYBdhLWcg3wo4yd#15163136 - Martin Smith
1
这可能以意想不到的方式发挥作用,也是一个已记录的反模式 - Thom A
即使这个方法能够运行,它的速度也比其他基于集合的解决方案慢得多。人们一直知道这是一个不受支持的技巧,即使在它首次出现的2000年代也是如此。 - Panagiotis Kanavos

34

SQL Server 2017 中有一个新的方法:

SELECT STRING_AGG (column, ',') AS column FROM Table;

这将为您产生1,3,5,9


13
select  stuff(list,1,1,'')
from    (
        select  ',' + cast(col1 as varchar(16)) as [text()]
        from    YourTable
        for     xml path('')
        ) as Sub(list)

在 SQL Fiddle 上的示例。


5

当前被认可的答案不能用于多个分组。
在需要对列行值的类别进行操作时,请尝试使用以下代码。

假设我有以下数据:

+---------+-----------+
| column1 |  column2  |
+---------+-----------+
| cat     | Felon     |
| cat     | Purz      |
| dog     | Fido      |
| dog     | Beethoven |
| dog     | Buddy     |
| bird    | Tweety    |
+---------+-----------+

And I want this as my output:

+------+----------------------+
| type |        names         |
+------+----------------------+
| cat  | Felon,Purz           |
| dog  | Fido,Beethoven,Buddy |
| bird | Tweety               |
+------+----------------------+

(如果你在跟进:)

create table #column_to_list (column1 varchar(30), column2 varchar(30))
insert into #column_to_list
values 
('cat','Felon'),
('cat','Purz'),
('dog','Fido'),
('dog','Beethoven'),
('dog','Buddy'),
('bird','Tweety')

现在,我不想深入讨论所有的语法问题,但是正如您所看到的,这为我们做到了初始的技巧:

select ',' + cast(column2 as varchar(255)) as [text()]  
from #column_to_list sub
where column1 = 'dog'
for xml path('')
--Using "as [text()]" here is specific to the “for XML” line after our where clause and we can’t give a name to our selection, hence the weird column_name

输出:

+------------------------------------------+
| XML_F52E2B61-18A1-11d1-B105-00805F49916B |
+------------------------------------------+
| ,Fido,Beethoven,Buddy                    |
+------------------------------------------+

你可以看到它的局限性,因为它只针对一个分组进行操作(其中 column1 = 'dog'),并在前面留下了一个逗号,此外它的命名方式也很奇怪。
因此,首先让我们使用“stuff”函数来处理前导逗号,并将列命名为 stuff_list:
select stuff([list],1,1,'') as stuff_list
from (select ',' + cast(column2 as varchar(255)) as [text()]
         from #column_to_list sub
         where column1 = 'dog'
         for xml path('')
         ) sub_query([list]) 
--"sub_query([list])" just names our column as '[list]' so we can refer to it in the stuff function.  

输出:

+----------------------+
|      stuff_list      |
+----------------------+
| Fido,Beethoven,Buddy |
+----------------------+

最后,让我们将其整合到一个select语句中,注意要引用top_query别名来定义我们想要的column1(这里是第5行):

select top_query.column1, 
          (select stuff([list],1,1,'') as stuff_list
         from (select ',' + cast(column2 as varchar(255)) as [text()]
                  from #column_to_list sub
                  where sub.column1 = top_query.column1
                  for xml path('')
                  ) sub_query([list])
              ) as pet_list
from  #column_to_list top_query
group by column1
order by column1

输出:

+---------+----------------------+
| column1 |       pet_list       |
+---------+----------------------+
| bird    | Tweety               |
| cat     | Felon,Purz           |
| dog     | Fido,Beethoven,Buddy |
+---------+----------------------+

我们完成了。

您可以在此处阅读更多信息:


5
SELECT  CAST(<COLUMN Name> AS VARCHAR(3)) + ','
FROM    <TABLE Name>
FOR     XML PATH('')

1
您可以使用以下方法:
select
STUFF(
        (
        select ', ' + CONVERT(varchar(10), ID) FROM @temp
        where ID<50
group by ID for xml path('')
        ), 1, 2, '') as IDs

实现:

Declare @temp Table(
ID int
)
insert into @temp
(ID)
values
(1)
insert into @temp
(ID)
values
(3)
insert into @temp
(ID)
values
(5)
insert into @temp
(ID)
values
(9)

 select
STUFF(
        (
        select ', ' + CONVERT(varchar(10), ID) FROM @temp
        where ID<50
group by ID for xml path('')
        ), 1, 2, '') as IDs

结果将会是:

enter image description here


1

--------------------------- 简单易懂,我喜欢 ----------------

SELECT STUFF((
        select ','+ name 
        from tblUsers
        FOR XML PATH('')
        )
        ,1,1,'') AS names

name
---------
mari, joan, carls
---------

1
这是创建可重用列到逗号分隔字符串的尝试。在本例中,我仅需要带有值的字符串,而不需要空字符串或null。
首先,我创建了一个用户定义类型,它是一个一列表格。
-- ================================
-- Create User-defined Table Type
-- ================================
USE [RSINET.MVC]
GO

-- Create the data type
CREATE TYPE [dbo].[SingleVarcharColumn] AS TABLE 
(
    data NVARCHAR(max)
)
GO

类型的真正目的是简化创建标量函数,将列转换为逗号分隔值。
-- ================================================
-- Template generated from Template Explorer using:
-- Create Scalar Function (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the function.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  Rob Peterson        
-- Create date: 8-26-2015
-- Description: This will take a single varchar column and convert it to
-- comma separated values.
-- =============================================
CREATE FUNCTION fnGetCommaSeparatedString 
(
    -- Add the parameters for the function here
    @column AS [dbo].[SingleVarcharColumn] READONLY
)
RETURNS VARCHAR(max)
AS
BEGIN
-- Declare the return variable here
DECLARE @result VARCHAR(MAX)
DECLARE @current VARCHAR(MAX)
DECLARE @counter INT
DECLARE @c CURSOR

SET @result = ''
SET @counter = 0
-- Add the T-SQL statements to compute the return value here
SET @c = CURSOR FAST_FORWARD
    FOR SELECT COALESCE(data,'') FROM @column
    OPEN @c
    FETCH NEXT FROM @c
    INTO @current
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @result <> '' AND @current <> '' SET @result = @result + ',' + @current
        IF @result = '' AND @current <> '' SET @result = @current
    FETCH NEXT FROM @c
    INTO @current
    END
    CLOSE @c
    DEALLOCATE @c
-- Return the result of the function
RETURN @result

END
GO

现在,要使用它。我选择要转换为逗号分隔字符串的列到SingleVarcharColumn类型中。
DECLARE @s as SingleVarcharColumn

INSERT INTO @s VALUES ('rob')
INSERT INTO @s VALUES ('paul')
INSERT INTO @s VALUES ('james')
INSERT INTO @s VALUES (null)


INSERT INTO @s
SELECT iClientID FROM [dbo].tClient

SELECT [dbo].fnGetCommaSeparatedString(@s)

要获得这样的结果。

罗布,保罗,詹姆斯,1,9,10,11,12,13,14,15,16,18,19,23,26,27,28,29,30,31,32,34,35,36,37,38,39,40,41,42,44,45,46,47,48,49,50,52,53,54,56,57,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78,81,82,83,84,87,88,90,91,92,93,94,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,120,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159

我将SingleVarcharColumn类型的数据列改为了NVARCHAR(MAX),这可能会影响性能,但我需要的是灵活性,并且对于我的目的来说运行得足够快。如果它是一个varchar并且具有固定和较小的宽度,那么它可能会更快,但我没有测试过。


像这样的游标方法比任何基于集合的方法都要慢。Aaron Bertrand在2011年进行了一项基准测试,并在之后的几年中使用更多技术进行了重复测试。如预期,游标始终表现得比其他方法差很多倍。 - Panagiotis Kanavos

-1

使用最简单的方法来完成这个任务-

SELECT GROUP_CONCAT(Column) from table

GROUP_CONCAT 不是一个被识别的内建函数 | Microsoft SQL Server Enterprise 14.0.3370.1 - Leo Gurdian
在SQL Server中的等效函数是STRING_AGG。 - Panagiotis Kanavos

-1
ALTER PROCEDURE [dbo].[spConvertir_CampoACadena]( @nomb_tabla   varchar(30),
                          @campo_tabla  varchar(30),
                          @delimitador  varchar(5),
                          @respuesta    varchar(max) OUTPUT
)
AS
DECLARE @query      varchar(1000),
    @cadena     varchar(500)
BEGIN
  SET @query = 'SELECT @cadena  = COALESCE(@cadena + '''+ @delimitador +''', '+ '''''' +') + '+ @campo_tabla + ' FROM '+@nomb_tabla
  --select @query
  EXEC(@query)
  SET @respuesta = @cadena  
END

这似乎与问题没有太大关系,但即使有关系,请写下您发布的代码的一些解释。纯代码转储并不是非常有用的。 - Ajean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接