在MicrosoftSQLServer2005中模拟group_concat MySQL函数?
我正在尝试将一个基于MySQL的应用程序迁移到MicrosoftSQLServer2005(不是出于选择,但这就是生活) 在最初的应用程序中,我们几乎完全使用了符合ANSI-SQL的语句,但有一个显著的例外——我们相当频繁地使用MySQL的在MicrosoftSQLServer2005中模拟group_concat MySQL函数?,sql,sql-server,sql-server-2005,string-aggregation,Sql,Sql Server,Sql Server 2005,String Aggregation,我正在尝试将一个基于MySQL的应用程序迁移到MicrosoftSQLServer2005(不是出于选择,但这就是生活) 在最初的应用程序中,我们几乎完全使用了符合ANSI-SQL的语句,但有一个显著的例外——我们相当频繁地使用MySQL的group\u concat函数 顺便说一句,group_concat是这样做的:给定一个员工姓名和项目表 SELECT empName, projID FROM project_members; 返回: ANDY | A100 ANDY | B
group\u concat
函数
顺便说一句,group_concat是这样做的:给定一个员工姓名和项目表
SELECT empName, projID FROM project_members;
返回:
ANDY | A100
ANDY | B391
ANDY | X010
TOM | A100
TOM | A510
ANDY | A100 / B391 / X010
TOM | A100 / A510
。。。下面是您通过group_concat获得的信息:
SELECT
empName, group_concat(projID SEPARATOR ' / ')
FROM
project_members
GROUP BY
empName;
返回:
ANDY | A100
ANDY | B391
ANDY | X010
TOM | A100
TOM | A510
ANDY | A100 / B391 / X010
TOM | A100 / A510
所以我想知道的是:有没有可能在SQL Server中编写一个用户定义的函数来模拟group\u concat
的功能
我几乎没有使用UDF、存储过程或诸如此类的东西的经验,只是简单的SQL,所以请在解释太多的方面出错:)没有真正简单的方法来做到这一点。尽管有很多想法 :
或者,如果数据可能包含以下代码中的字符(如
),则必须在部署之前在项目属性上设置PermissionLevel=External,并通过运行“ALTER DATABASE_name SET TRUSTHY ON”
收益率:A、B、C、D可能太晚了,现在还不能受益,但这不是最简单的方法吗
SELECT empName, projIDs = replace
((SELECT Surname AS [data()]
FROM project_members
WHERE empName = a.empName
ORDER BY empName FOR xml path('')), ' ', REQUIRED SEPERATOR)
FROM project_members a
WHERE empName IS NOT NULL
GROUP BY empName
关于J Hardiman的答案,那么:
SELECT empName, projIDs=
REPLACE(
REPLACE(
(SELECT REPLACE(projID, ' ', '-somebody-puts-microsoft-out-of-his-misery-please-') AS [data()] FROM project_members WHERE empName=a.empName FOR XML PATH('')),
' ',
' / '),
'-somebody-puts-microsoft-out-of-his-misery-please-',
' ')
FROM project_members a WHERE empName IS NOT NULL GROUP BY empName
顺便问一下,使用“姓氏”是打字错误还是我不理解这里的一个概念
无论如何,非常感谢大家,因为这为我节省了不少时间:)尝试了这些,但对于我在MS SQL Server 2005中的目的,以下内容非常有用,我在
@马克,正如你提到的,是空格字符给我带来了问题。我参加聚会可能有点晚,但这种方法对我有效,比合并方法更简单
SELECT STUFF(
(SELECT ',' + Column_Name
FROM Table_Name
FOR XML PATH (''))
, 1, 1, '')
要连接具有多个项目经理的项目中的所有项目经理名称,请执行以下操作:
SELECT a.project_id,a.project_name,Stuff((SELECT N'/ ' + first_name + ', '+last_name FROM projects_v
where a.project_id=project_id
FOR
XML PATH(''),TYPE).value('text()[1]','nvarchar(max)'),1,2,N''
) mgr_names
from projects_v a
group by a.project_id,a.project_name
看看Github上的项目,我想我做的正是您要搜索的:
此项目包含一组SQLCLR用户定义聚合函数(SQLCLR UDA),它们共同提供与MySQL组_CONCAT函数类似的功能。有多个函数可确保基于所需功能的最佳性能
SQL Server 2017引入了一个新的聚合函数
连接字符串表达式的值并放置分隔符
它们之间的值。分隔符不添加在字符串的末尾
连接的元素可以通过在组内追加来排序(按某些表达式排序)
对于2005-2016版我通常在接受的答案中使用XML方法
但是,在某些情况下,这可能会失败。例如,如果要连接的数据包含CHAR(29)
您会看到
FOR XML无法序列化数据…因为它
包含XML中不允许的字符(0x001D)
可以处理所有字符的更健壮的方法是使用CLR聚合。但是,使用这种方法对连接的元素应用排序更为困难
在生产代码中,赋值给变量的方法是并且应该避免的。对于我的谷歌同事来说,这里有一个非常简单的即插即用解决方案,在与更复杂的解决方案进行了一段时间的斗争后,它对我很有效:
SELECT
distinct empName,
NewColumnName=STUFF((SELECT ','+ CONVERT(VARCHAR(10), projID )
FROM returns
WHERE empName=t.empName FOR XML PATH('')) , 1 , 1 , '' )
FROM
returns t
请注意,我必须将ID转换为VARCHAR,以便将其连接为字符串。如果不必这样做,这里有一个更简单的版本:
SELECT
distinct empName,
NewColumnName=STUFF((SELECT ','+ projID
FROM returns
WHERE empName=t.empName FOR XML PATH('')) , 1 , 1 , '' )
FROM
returns t
这一切归功于:
更新2020:SQL Server 2016+JSON序列化和反序列化示例
OP提供的数据插入名为#project#u members的临时表中
drop table if exists #project_members;
create table #project_members(
empName varchar(20) not null,
projID varchar(20) not null);
go
insert #project_members(empName, projID) values
('ANDY', 'A100'),
('ANDY', 'B391'),
('ANDY', 'X010'),
('TOM', 'A100'),
('TOM', 'A510');
如何使用包含projID的嵌套数组将此数据序列化为单个JSON字符串
select empName, (select pm_json.projID
from #project_members pm_json
where pm.empName=pm_json.empName
for json path, root('projList')) projJSON
from #project_members pm
group by empName
for json path;
select wj.empName, oj.projID
from
#project_members_with_json wj
cross apply
openjson(wj.projJSON, '$.projList') with (projID varchar(20)) oj;
结果
'[
{
"empName": "ANDY",
"projJSON": {
"projList": [
{ "projID": "A100" },
{ "projID": "B391" },
{ "projID": "X010" }
]
}
},
{
"empName": "TOM",
"projJSON": {
"projList": [
{ "projID": "A100" },
{ "projID": "A510" }
]
}
}
]'
如何将此数据从单个JSON字符串反序列化回其原始行和列
declare @json nvarchar(max)=N'[{"empName":"ANDY","projJSON":{"projList":[{"projID":"A100"},
{"projID":"B391"},{"projID":"X010"}]}},{"empName":"TOM","projJSON":
{"projList":[{"projID":"A100"},{"projID":"A510"}]}}]';
select oj.empName, noj.projID
from openjson(@json) with (empName varchar(20),
projJSON nvarchar(max) as json) oj
cross apply openjson(oj.projJSON, '$.projList') with (projID varchar(20)) noj;
结果
empName projID
ANDY A100
ANDY B391
ANDY X010
TOM A100
TOM A510
empName projJSON
ANDY {"projList":[{"projID":"A100"},{"projID":"B391"},{"projID":"X010"}]}
TOM {"projList":[{"projID":"A100"},{"projID":"A510"}]}
empName projID
ANDY A100
ANDY B391
ANDY X010
TOM A100
TOM A510
如何将唯一的empName持久化到表中,并将projID存储在嵌套的JSON数组中
drop table if exists #project_members_with_json;
create table #project_members_with_json(
empName varchar(20) unique not null,
projJSON nvarchar(max) not null);
go
insert #project_members_with_json(empName, projJSON)
select empName, (select pm_json.projID
from #project_members pm_json
where pm.empName=pm_json.empName
for json path, root('projList'))
from #project_members pm
group by empName;
结果
empName projID
ANDY A100
ANDY B391
ANDY X010
TOM A100
TOM A510
empName projJSON
ANDY {"projList":[{"projID":"A100"},{"projID":"B391"},{"projID":"X010"}]}
TOM {"projList":[{"projID":"A100"},{"projID":"A510"}]}
empName projID
ANDY A100
ANDY B391
ANDY X010
TOM A100
TOM A510
如何从具有唯一empName和嵌套JSON数组列(包含projID的)的表反序列化
select empName, (select pm_json.projID
from #project_members pm_json
where pm.empName=pm_json.empName
for json path, root('projList')) projJSON
from #project_members pm
group by empName
for json path;
select wj.empName, oj.projID
from
#project_members_with_json wj
cross apply
openjson(wj.projJSON, '$.projList') with (projID varchar(20)) oj;
结果
empName projID
ANDY A100
ANDY B391
ANDY X010
TOM A100
TOM A510
empName projJSON
ANDY {"projList":[{"projID":"A100"},{"projID":"B391"},{"projID":"X010"}]}
TOM {"projList":[{"projID":"A100"},{"projID":"A510"}]}
empName projID
ANDY A100
ANDY B391
ANDY X010
TOM A100
TOM A510
这个例子对我很有效,但我尝试进行另一次聚合,但没有成功,给了我一个错误:“在FROM子句中多次指定了相关名称'pre_trimmed'。“'pre_trimmed'只是子查询的别名。别名对于子查询是必需的,并且必须是唯一的,因此对于另一个子查询,请将其更改为唯一的…您是否可以显示一个没有表_名称作为列名的示例?这很令人困惑。有趣。我已经完成了手头的项目,但我将尝试一下这种方法。谢谢很好的技巧——唯一的问题是对于带有空格的姓氏,它将用分隔符替换空格。马克,我自己也遇到过这样的问题。不幸的是,在MSSQL跟上时代并引入GROUP_CONCAT之前,这是我能够为这里需要的东西想出的开销最少的方法。谢谢!这里有一个SQL FIDLE显示它的工作原理:几个方便的链接:这是一个老问题,但我喜欢。可能的重复-这篇文章的范围更广,所以我会选择这篇文章作为规范可能的重复,你如何知道应该按哪个顺序构建列表,例如,您显示的是A100/B391/X010,但鉴于关系数据库中没有隐含的排序,它也可能很容易是X010/A100/B391或任何其他组合。如果您问我,回答会很不友好,根本没有帮助。现在才看到这一点。。。我不是故意的,当时我对sql非常失望