考虑一个包含名称的数据库表,其中包含三行:
Peter
Paul
Mary
有没有一种简单的方法可以将其转换为Peter, Paul, Mary
的单个字符串?
答案 0 :(得分:1257)
如果您使用的是SQL Server 2017或Azure,请参阅Mathieu Renda answer。
当我尝试使用一对多关系加入两个表时,我遇到了类似的问题。在SQL 2005中,我发现XML PATH
方法可以非常容易地处理行的连接。
如果有一个名为STUDENTS
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
我预期的结果是:
SubjectID StudentName
---------- -------------
1 Mary, John, Sam
2 Alaina, Edward
我使用了以下T-SQL
:
SELECT Main.SubjectID,
LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
(
SELECT DISTINCT ST2.SubjectID,
(
SELECT ST1.StudentName + ',' AS [text()]
FROM dbo.Students ST1
WHERE ST1.SubjectID = ST2.SubjectID
ORDER BY ST1.SubjectID
FOR XML PATH ('')
) [Students]
FROM dbo.Students ST2
) [Main]
如果您可以在开头连接逗号并使用substring
跳过第一个逗号,那么您可以以更紧凑的方式执行相同的操作,因此您不需要执行子查询:
SELECT DISTINCT ST2.SubjectID,
SUBSTRING(
(
SELECT ','+ST1.StudentName AS [text()]
FROM dbo.Students ST1
WHERE ST1.SubjectID = ST2.SubjectID
ORDER BY ST1.SubjectID
FOR XML PATH ('')
), 2, 1000) [Students]
FROM dbo.Students ST2
答案 1 :(得分:949)
此答案可能会返回unexpected results要获得一致的结果,请使用其他答案中详述的FOR XML PATH方法之一。
使用COALESCE
:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
只是一些解释(因为这个答案似乎得到了相对规律的观点):
1)无需使用空字符串值初始化@Names
。
2)最后无需剥去额外的分隔符。
@Names
NULL ,并且下一行将再次作为空字符串重新开始。使用以下两种解决方案之一轻松修复:DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL
或:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') +
ISNULL(Name, 'N/A')
FROM People
根据您想要的行为(第一个选项只是过滤 NULL ,第二个选项将它们保留在列表中并带有标记消息[用适合的任何内容替换'N / A'你])。
答案 2 :(得分:334)
在MS SQL Server中通过XML
data()
命令尚未显示的一种方法是:
假设名为NameList的表有一列名为FName,
SELECT FName + ', ' AS 'data()'
FROM NameList
FOR XML PATH('')
返回:
"Peter, Paul, Mary, "
只能处理额外的逗号。
编辑:从@ NReilingh的评论中采用,您可以使用以下方法删除尾随逗号。假设表名和列名相同:
STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
答案 3 :(得分:287)
从下一版本的SQL Server开始,我们最终可以跨行连接,而不必诉诸任何变量或XML witchery。
不分组
SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;
分组:
SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
使用分组和子分类
SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
答案 4 :(得分:267)
SELECT Stuff(
(SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
您可以使用FOR JSON syntax
即。
SELECT per.ID,
Emails = JSON_VALUE(
REPLACE(
(SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._'
)
FROM Person per
结果将变为
Id Emails
1 abc@gmail.com
2 NULL
3 def@gmail.com, xyz@gmail.com
这甚至会使您的数据包含无效的XML字符
'"},{"_":"'
是安全的,因为如果您的数据包含'"},{"_":"',
,则会转义为"},{\"_\":\"
您可以将', '
替换为任何字符串分隔符
您可以使用新的STRING_AGG function
答案 5 :(得分:111)
在MySQL中有一个函数GROUP_CONCAT(),它允许您连接多行的值。例如:
SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people
FROM users
WHERE id IN (1,2,3)
GROUP BY a
答案 6 :(得分:54)
使用 COALESCE - Learn more from here
例如:
102
103
104
然后在sql server中编写以下代码,
Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers
SELECT @Numbers = COALESCE(@Numbers + ',', '') + Number
FROM TableName where Number IS NOT NULL
SELECT @Numbers
输出将是:
102,103,104
答案 7 :(得分:47)
Postgres数组非常棒。例如:
创建一些测试数据:
postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');
INSERT 0 3
test=# select * from names;
name
-------
Peter
Paul
Mary
(3 rows)
将它们聚合在一个数组中:
test=# select array_agg(name) from names;
array_agg
-------------------
{Peter,Paul,Mary}
(1 row)
将数组转换为逗号分隔的字符串:
test=# select array_to_string(array_agg(name), ', ') from names;
array_to_string
-------------------
Peter, Paul, Mary
(1 row)
DONE
自PostgreSQL 9.0以来,它是even easier。
答案 8 :(得分:45)
Oracle 11g第2版支持LISTAGG功能。文档here。
COLUMN employees FORMAT A50
SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM emp
GROUP BY deptno;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
如果结果字符串有可能超过4000个字符,请小心实现此功能。它会引发异常。如果是这种情况,则需要处理异常或滚动自己的函数,以防止连接的字符串超过4000个字符。
答案 9 :(得分:33)
在SQL Server 2005及更高版本中,使用下面的查询来连接行。
DECLARE @t table
(
Id int,
Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d'
SELECT ID,
stuff(
(
SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'')
FROM (SELECT DISTINCT ID FROM @t ) t
答案 10 :(得分:26)
我在家里无法访问SQL Server,所以我猜这里的语法,但它或多或少:
DECLARE @names VARCHAR(500)
SELECT @names = @names + ' ' + Name
FROM Names
答案 11 :(得分:25)
你需要创建一个变量来保存你的最终结果并选择它,就像这样。
DECLARE @char VARCHAR(MAX);
SELECT @char = COALESCE(@char + ', ' + [column], [column])
FROM [table];
PRINT @char;
答案 12 :(得分:24)
建议使用递归CTE解决方案,但不提供代码。下面的代码是递归CTE的一个示例 - 请注意,尽管结果与问题匹配,但数据完全与给定描述不匹配,因为我假设您确实希望这样做在行组上,而不是表中的所有行。更改它以匹配表中的所有行留给读者练习。
;with basetable as
( SELECT id, CAST(name as varchar(max))name,
ROW_NUMBER() OVER(Partition By id order by seq) rw,
COUNT(*) OVER (Partition By id) recs
FROM (VALUES (1, 'Johnny', 1), (1,'M', 2),
(2,'Bill', 1), (2, 'S.', 4), (2, 'Preston', 5), (2, 'Esq.', 6),
(3, 'Ted', 1), (3,'Theodore', 2), (3,'Logan', 3),
(4, 'Peter', 1), (4,'Paul', 2), (4,'Mary', 3)
)g(id, name, seq)
),
rCTE as (
SELECT recs, id, name, rw from basetable where rw=1
UNION ALL
SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw+1
FROM basetable b
inner join rCTE r
on b.id = r.id and b.rw = r.rw+1
)
SELECT name FROM rCTE
WHERE recs = rw and ID=4
答案 13 :(得分:23)
从PostgreSQL 9.0开始,这很简单:
select string_agg(name, ',')
from names;
在9.0 array_agg()
之前的版本中,可以使用hgmnz
答案 14 :(得分:21)
在SQL Server vNext中,这将使用STRING_AGG函数构建,请在此处阅读更多相关信息: https://msdn.microsoft.com/en-us/library/mt790580.aspx
答案 15 :(得分:17)
一个随时可用的解决方案,没有额外的逗号:
select substring(
(select ', '+Name AS 'data()' from Names for xml path(''))
,3, 255) as "MyList"
空列表将导致NULL值。 通常,您会将列表插入表格列或程序变量中:根据需要调整255最大长度。
(Diwakar和Jens Frandsen提供了很好的答案,但需要改进。)
答案 16 :(得分:17)
使用XML帮助我用逗号分隔行。对于额外的逗号,我们可以使用SQL Server的替换功能。使用AS'data()'代替添加逗号,将使用空格连接行,稍后可以用逗号替换为下面的语法。
REPLACE(
(select FName AS 'data()' from NameList for xml path(''))
, ' ', ', ')
答案 17 :(得分:12)
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')
以下是一个示例:
DECLARE @t TABLE (name VARCHAR(10))
INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
--Peter, Paul, Mary
答案 18 :(得分:10)
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)
这会将流浪逗号放在开头。
但是,如果您需要其他列,或者要CSV子表,则需要将其包装在标量用户定义字段(UDF)中。
你也可以在SELECT子句中使用XML路径作为相关子查询(但是我必须等到我回去工作,因为Google不在家做工作: - )
答案 19 :(得分:9)
通过其他答案,阅读答案的人必须知道特定的域表,例如车辆或学生。必须创建表并填充数据以测试解决方案。
下面是一个使用SQL Server“Information_Schema.Columns”表的示例。通过使用此解决方案,无需创建表或添加数据。此示例为数据库中的所有表创建逗号分隔的列名列表。
SELECT
Table_Name
,STUFF((
SELECT ',' + Column_Name
FROM INFORMATION_SCHEMA.Columns Columns
WHERE Tables.Table_Name = Columns.Table_Name
ORDER BY Column_Name
FOR XML PATH ('')), 1, 1, ''
)Columns
FROM INFORMATION_SCHEMA.Columns Tables
GROUP BY TABLE_NAME
答案 20 :(得分:8)
在 ms sql Server 2017 或更高版本中,您可以使用 STRING_AGG() 函数生成逗号分隔的 值。请查看下面举一个例子。
SELECT
VendorId,STRING_AGG(FirstName,',') UsersName FROM
Users
where VendorId!=9 GROUP BY VendorId
答案 21 :(得分:7)
对于Oracle DB,请参阅此问题:How can multiple rows be concatenated into one in Oracle without creating a stored procedure?
最佳答案似乎是@Emmanuel,使用Oracle 11g第2版及更高版本中提供的内置LISTAGG()函数。
SELECT question_id,
LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id
正如@ user762952指出的那样,根据Oracle的文档http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php,WM_CONCAT()函数也是一个选项。它似乎很稳定,但Oracle明确建议不要将它用于任何应用程序SQL,因此使用风险自负。
除此之外,你必须编写自己的功能;上面的Oracle文档提供了如何执行此操作的指南。
答案 22 :(得分:7)
我真的很喜欢Dana's answer的优雅。只想完成它。
DECLARE @names VARCHAR(MAX)
SET @names = ''
SELECT @names = @names + ', ' + Name FROM Names
-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
答案 23 :(得分:6)
要避免空值,可以使用CONCAT()
DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name)
FROM Names
select @names
答案 24 :(得分:6)
此答案需要服务器中的某些权限才能正常工作。
Assemblies对你来说是个不错的选择。有很多网站可以解释如何创建它。我认为非常好解释的是one
如果您愿意,我已经创建了程序集,并且可以下载DLL here。
下载后,您需要在SQL Server中运行以下脚本:
CREATE Assembly concat_assembly
AUTHORIZATION dbo
FROM '<PATH TO Concat.dll IN SERVER>'
WITH PERMISSION_SET = SAFE;
GO
CREATE AGGREGATE dbo.concat (
@Value NVARCHAR(MAX)
, @Delimiter NVARCHAR(4000)
) RETURNS NVARCHAR(MAX)
EXTERNAL Name concat_assembly.[Concat.Concat];
GO
sp_configure 'clr enabled', 1;
RECONFIGURE
观察服务器可以访问程序集的路径。由于您已成功完成所有步骤,因此可以使用以下函数:
SELECT dbo.Concat(field1, ',')
FROM Table1
希望它有所帮助!!!
答案 25 :(得分:5)
如果你想处理空值,你可以通过添加一个where子句或在第一个周围添加另一个COALESCE来实现。
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
答案 26 :(得分:5)
我通常使用select这样来连接SQL Server中的字符串:
with lines as
(
select
row_number() over(order by id) id, -- id is a line id
line -- line of text.
from
source -- line source
),
result_lines as
(
select
id,
cast(line as nvarchar(max)) line
from
lines
where
id = 1
union all
select
l.id,
cast(r.line + N', ' + l.line as nvarchar(max))
from
lines l
inner join
result_lines r
on
l.id = r.id + 1
)
select top 1
line
from
result_lines
order by
id desc
答案 27 :(得分:5)
MySQL完成示例:
我们的用户可以有很多数据,我们希望有一个输出,我们可以在列表中看到所有用户数据:
<强>结果:强>
___________________________
| id | rowList |
|-------------------------|
| 0 | 6, 9 |
| 1 | 1,2,3,4,5,7,8,1 |
|_________________________|
表格设置:
CREATE TABLE `Data` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;
INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);
CREATE TABLE `User` (
`id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `User` (`id`) VALUES
(0),
(1);
查询:
SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id
答案 28 :(得分:4)
这也很有用
create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')
DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test
返回
Peter,Paul,Mary
答案 29 :(得分:4)
在Oracle中,它是wm_concat
。我相信此功能在10g release及更高版本中可用。
答案 30 :(得分:4)
答案 31 :(得分:3)
以下是实现此目标的完整解决方案:
-- Table Creation
CREATE TABLE Tbl
( CustomerCode VARCHAR(50)
, CustomerName VARCHAR(50)
, Type VARCHAR(50)
,Items VARCHAR(50)
)
insert into Tbl
SELECT 'C0001','Thomas','BREAKFAST','Milk'
union SELECT 'C0001','Thomas','BREAKFAST','Bread'
union SELECT 'C0001','Thomas','BREAKFAST','Egg'
union SELECT 'C0001','Thomas','LUNCH','Rice'
union SELECT 'C0001','Thomas','LUNCH','Fish Curry'
union SELECT 'C0001','Thomas','LUNCH','Lessy'
union SELECT 'C0002','JOSEPH','BREAKFAST','Bread'
union SELECT 'C0002','JOSEPH','BREAKFAST','Jam'
union SELECT 'C0002','JOSEPH','BREAKFAST','Tea'
union SELECT 'C0002','JOSEPH','Supper','Tea'
union SELECT 'C0002','JOSEPH','Brunch','Roti'
-- function creation
GO
CREATE FUNCTION [dbo].[fn_GetItemsByType]
(
@CustomerCode VARCHAR(50)
,@Type VARCHAR(50)
)
RETURNS @ItemType TABLE ( Items VARCHAR(5000) )
AS
BEGIN
INSERT INTO @ItemType(Items)
SELECT STUFF((SELECT distinct ',' + [Items]
FROM Tbl
WHERE CustomerCode = @CustomerCode
AND Type=@Type
FOR XML PATH(''))
,1,1,'') as Items
RETURN
END
GO
-- fianl Query
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Type)
from Tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT CustomerCode,CustomerName,' + @cols + '
from
(
select
distinct CustomerCode
,CustomerName
,Type
,F.Items
FROM Tbl T
CROSS APPLY [fn_GetItemsByType] (T.CustomerCode,T.Type) F
) x
pivot
(
max(Items)
for Type in (' + @cols + ')
) p '
execute(@query)
答案 32 :(得分:3)
此方法仅适用于Teradata Aster数据库,因为它使用其NPATH功能。
再次,我们有表学生
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
然后使用NPATH,它只是单个SELECT:
SELECT * FROM npath(
ON Students
PARTITION BY SubjectID
ORDER BY StudentName
MODE(nonoverlapping)
PATTERN('A*')
SYMBOLS(
'true' as A
)
RESULT(
FIRST(SubjectID of A) as SubjectID,
ACCUMULATE(StudentName of A) as StudentName
)
);
结果:
SubjectID StudentName
---------- -------------
1 [John, Mary, Sam]
2 [Alaina, Edward]
答案 33 :(得分:3)
并不是说我对表现进行了任何分析,因为我的名单少于10个项目但是在看了30个奇怪的答案之后我感到很惊讶我仍然对类似的答案感到惊讶已经给出类似于单个组使用COALESCE的答案列表,甚至不必设置我的变量(无论如何默认为NULL),并假设我的源数据表中的所有条目都是非空白的:
DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData
我相信COALESCE内部使用相同的想法。 让我们希望MS不要改变这一点。
答案 34 :(得分:3)
- SQL Server 2005 +
CREATE TABLE dbo.Students
(
StudentId INT
, Name VARCHAR(50)
, CONSTRAINT PK_Students PRIMARY KEY (StudentId)
);
CREATE TABLE dbo.Subjects
(
SubjectId INT
, Name VARCHAR(50)
, CONSTRAINT PK_Subjects PRIMARY KEY (SubjectId)
);
CREATE TABLE dbo.Schedules
(
StudentId INT
, SubjectId INT
, CONSTRAINT PK__Schedule PRIMARY KEY (StudentId, SubjectId)
, CONSTRAINT FK_Schedule_Students FOREIGN KEY (StudentId) REFERENCES dbo.Students (StudentId)
, CONSTRAINT FK_Schedule_Subjects FOREIGN KEY (SubjectId) REFERENCES dbo.Subjects (SubjectId)
);
INSERT dbo.Students (StudentId, Name) VALUES
(1, 'Mary')
, (2, 'John')
, (3, 'Sam')
, (4, 'Alaina')
, (5, 'Edward')
;
INSERT dbo.Subjects (SubjectId, Name) VALUES
(1, 'Physics')
, (2, 'Geography')
, (3, 'French')
, (4, 'Gymnastics')
;
INSERT dbo.Schedules (StudentId, SubjectId) VALUES
(1, 1) --Mary, Physics
, (2, 1) --John, Physics
, (3, 1) --Sam, Physics
, (4, 2) --Alaina, Geography
, (5, 2) --Edward, Geography
;
SELECT
sub.SubjectId
, sub.Name AS [SubjectName]
, ISNULL( x.Students, '') AS Students
FROM
dbo.Subjects sub
OUTER APPLY
(
SELECT
CASE ROW_NUMBER() OVER (ORDER BY stu.Name) WHEN 1 THEN '' ELSE ', ' END
+ stu.Name
FROM
dbo.Students stu
INNER JOIN dbo.Schedules sch
ON stu.StudentId = sch.StudentId
WHERE
sch.SubjectId = sub.SubjectId
ORDER BY
stu.Name
FOR XML PATH('')
) x (Students)
;
答案 35 :(得分:2)
这个怎么样:
ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'
考虑到您认为会出现的最大项目数,“300”可以是任何宽度。
答案 36 :(得分:2)
在SQL Server中可以做到的一种方法是将表内容作为XML(对于XML raw)返回,将结果转换为字符串,然后用“,”替换标记。
答案 37 :(得分:1)
SELECT PageContent = Stuff(
( SELECT PageContent
FROM dbo.InfoGuide
WHERE CategoryId = @CategoryId
AND SubCategoryId = @SubCategoryId
for xml path(''), type
).value('.[1]','nvarchar(max)'),
1, 1, '')
FROM dbo.InfoGuide info
答案 38 :(得分:1)
使用TABLE类型非常容易。我们假设您的表名为Students
,它有name
列。
declare @rowsCount INT
declare @i INT = 1
declare @names varchar(max) = ''
DECLARE @MyTable TABLE
(
Id int identity,
Name varchar(500)
)
insert into @MyTable select name from Students
set @rowsCount = (select COUNT(Id) from @MyTable)
while @i < @rowsCount
begin
set @names = @names + ', ' + (select name from @MyTable where Id = @i)
set @i = @i + 1
end
select @names
此示例在MS SQL Server 2008 R2中进行了测试
答案 39 :(得分:1)
虽然为时已晚,已经有很多解决方案。这是MySQL的简单解决方案:
SELECT t1.id,
GROUP_CONCAT(t1.id) ids
FROM table t1 JOIN table t2 ON (t1.id = t2.id)
GROUP BY t1.id
答案 40 :(得分:1)
表格定义
CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;
让我们在此表中插入值
INSERT INTO NAMES VALUES('PETER');
INSERT INTO NAMES VALUES('PAUL');
INSERT INTO NAMES VALUES('MARY');
程序从这里开始
DECLARE
MAXNUM INTEGER;
CNTR INTEGER := 1;
C_NAME NAMES.NAME%TYPE;
NSTR VARCHAR2(50);
BEGIN
SELECT MAX(ROWNUM) INTO MAXNUM FROM NAMES;
LOOP
SELECT NAME INTO C_NAME FROM
(SELECT ROWNUM RW, NAME FROM NAMES ) P WHERE P.RW = CNTR;
NSTR := NSTR ||','||C_NAME;
CNTR := CNTR + 1;
EXIT WHEN CNTR > MAXNUM;
END LOOP;
dbms_output.put_line(SUBSTR(NSTR,2));
END;
结果
PETER,PAUL,MARY
答案 41 :(得分:1)
oracle还有几种方法,
create table name
(first_name varchar2(30));
insert into name values ('Peter');
insert into name values ('Paul');
insert into name values ('Mary');
Solution 1:
select substr(max(sys_connect_by_path (first_name, ',')),2) from (select rownum r, first_name from name ) n start with r=1 connect by prior r+1=r
o/p=> Peter,Paul,Mary
Soution 2:
select rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
o/p=> Peter,Paul,Mary
答案 42 :(得分:1)
@ User1460901您可以尝试这样的事情:
WITH cte_base AS (
SELECT CustomerCode, CustomerName,
CASE WHEN Typez = 'Breakfast' THEN Items ELSE NULL END AS 'BREAKFAST'
, CASE WHEN Typez = 'Lunch' THEN Items ELSE NULL END AS 'LUNCH'
FROM #Customer
)
SELECT distinct CustomerCode, CustomerName,
SUBSTRING(
(
SELECT ','+BREAKFAST AS [text()]
FROM cte_base b1
WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
ORDER BY b1.BREAKFAST
FOR XML PATH('')
), 2, 1000
) [BREAKFAST],
SUBSTRING(
(
SELECT ','+LUNCH AS [text()]
FROM cte_base b1
WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
ORDER BY b1.LUNCH
FOR XML PATH('')
), 2, 1000
) [LUNCH]
FROM cte_base b2
答案 43 :(得分:1)
使用递归查询,您可以做到:
-- Create example table
CREATE TABLE tmptable (NAME VARCHAR(30)) ;
-- Insert example data
INSERT INTO tmptable VALUES('PETER');
INSERT INTO tmptable VALUES('PAUL');
INSERT INTO tmptable VALUES('MARY');
-- Recurse query
with tblwithrank as (
select * , row_number() over(order by name) rang , count(*) over() NbRow
from tmptable
),
tmpRecursive as (
select *, cast(name as varchar(2000)) as AllName from tblwithrank where rang=1
union all
select f0.*, cast(f0.name + ',' + f1.AllName as varchar(2000)) as AllName
from tblwithrank f0 inner join tmpRecursive f1 on f0.rang=f1.rang +1
)
select AllName from tmpRecursive
where rang=NbRow
答案 44 :(得分:1)
在克里斯·谢弗(Chris Shaffer)答案之上
如果您的数据可能重复出现,例如
Tom
Ali
John
Ali
Tom
Mike
代替Tom,Ali,John,Ali,Tom,Mike
您可以使用DISTINCT避免重复并获取Tom,Ali,John,Mike
DECLARE @Names VARCHAR(8000)
SELECT DISTINCT @Names = COALESCE(@Names + ',', '') + Name
FROM People
WHERE Name IS NOT NULL
SELECT @Names
答案 45 :(得分:0)
我们可以按如下方式使用RECUSRSIVITY,WITH CTE和UNIION ALL
declare @mytable as table(id int identity(1,1), str nvarchar(100))
insert into @mytable values('Peter'),('Paul'),('Mary')
declare @myresult as table(id int,str nvarchar(max),ind int, R# int)
;with cte as(select id,cast(str as nvarchar(100)) as str, cast(0 as int) ind from @mytable
union all
select t2.id,cast(t1.str+',' +t2.str as nvarchar(100)) ,t1.ind+1 from cte t1 inner join @mytable t2 on t2.id=t1.id+1)
insert into @myresult select *,row_number() over(order by ind) R# from cte
select top 1 str from @myresult order by R# desc
答案 46 :(得分:0)
首先,您应该声明一个表变量,并用表数据填充它,然后,通过WHILE循环,逐一选择行并将其值添加到nvarchar(max)变量中。
Go
declare @temp table(
title nvarchar(50)
)
insert into @temp(title)
select p.Title from dbo.person p
--
declare @mainString nvarchar(max)
set @mainString = '';
--
while ((select count(*) from @temp) != 0)
begin
declare @itemTitle nvarchar(50)
set @itemTitle = (select top(1) t.Title from @temp t)
if @mainString = ''
begin
set @mainString = @itemTitle
end
else
begin
set @mainString = concat(@mainString,',',@itemTitle)
end
delete top(1) from @temp
end
print @mainString
答案 47 :(得分:-3)
取决于您的数据库供应商。 MySQL有concat_ws。 MS SQL Server希望您在客户端应用程序中执行此操作。
更新:您也可以在外部过程或UDF中执行此操作,可能是使用游标或调用CLR代码。
答案 48 :(得分:-4)
declare @phone varchar(max)=''
select @phone=@phone + mobileno +',' from members
select @phone