简化使用 FOR XML 连接列值的 SQL 视图语句
Simplify SQL view statement that concatenates column values with FOR XML
我已经为视图创建了一个语句,但我对它不满意,因为它多次包含相同的 SELECT。到目前为止,我无法调整声明以大大缩短它。也许你可以给我一个提示或告诉我我可以从哪里开始简化这个:
SELECT
STUFF((SELECT ', ' + t2.ToolId
FROM (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolId,
STUFF((SELECT ', ' + t2.ToolName
FROM (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolName,
t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
FROM (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
有没有办法避免重复以下部分?
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id
您可以使用 WITH 子句:
;with example as (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id
)
SELECT
STUFF((SELECT ', ' + t2.ToolId
FROM example t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolId,
STUFF((SELECT ', ' + t2.ToolName
FROM example t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolName,
t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
FROM example t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
SQL 引入了 Server 2016 STRING_AGG。假设原始查询中的所有子查询都相同,则 SQL Server 2016 中的等效项可能是:
select
STRING_AGG(Tool.ID,',') As ToolId,
STRING_AGG(Tool.Name,',') As ToolName,
TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
在较旧的 SQL 服务器版本中,我们可以使用 SQLCLR 字符串聚合函数获得类似的语法,例如 the one mentioned in Aaron Bertrand's article 关于字符串连接:
select
dbo.GROUP_CONCAT(Tool.ID) As ToolId,
dbo.GROUP_CONCAT(Tool.Name) As ToolName,
TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
我已经为视图创建了一个语句,但我对它不满意,因为它多次包含相同的 SELECT。到目前为止,我无法调整声明以大大缩短它。也许你可以给我一个提示或告诉我我可以从哪里开始简化这个:
SELECT
STUFF((SELECT ', ' + t2.ToolId
FROM (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolId,
STUFF((SELECT ', ' + t2.ToolName
FROM (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolName,
t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
FROM (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
有没有办法避免重复以下部分?
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id
您可以使用 WITH 子句:
;with example as (
SELECT CONVERT(NVARCHAR(36), Tool.Id) AS ToolId, Tool.Name AS ToolName, TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id
)
SELECT
STUFF((SELECT ', ' + t2.ToolId
FROM example t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolId,
STUFF((SELECT ', ' + t2.ToolName
FROM example t2
WHERE t1.GroupId = t2.GroupId AND t1.Id = t2.Id
ORDER BY t2.ToolId
FOR XML PATH(''), TYPE ).value('.', 'nvarchar(max)'), 1, 2, '') AS ToolName,
t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
FROM example t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
SQL 引入了 Server 2016 STRING_AGG。假设原始查询中的所有子查询都相同,则 SQL Server 2016 中的等效项可能是:
select
STRING_AGG(Tool.ID,',') As ToolId,
STRING_AGG(Tool.Name,',') As ToolName,
TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive
在较旧的 SQL 服务器版本中,我们可以使用 SQLCLR 字符串聚合函数获得类似的语法,例如 the one mentioned in Aaron Bertrand's article 关于字符串连接:
select
dbo.GROUP_CONCAT(Tool.ID) As ToolId,
dbo.GROUP_CONCAT(Tool.Name) As ToolName,
TGroup.Id AS GroupId, TGroup.Name AS GroupName, Base.Id,
Base.Position, Task.Definition, Task.IsEvaluationActive
FROM dbo.CustomTask AS Task INNER JOIN
dbo.TaskBase AS Base ON Task.Id = Base.Id LEFT OUTER JOIN
dbo.TaskGroup AS TGroup ON Base.TaskGroupId = TGroup.Id LEFT OUTER JOIN
dbo.ToolTaskGroupMapping AS Map ON TGroup.Id = Map.TaskGroupId LEFT OUTER JOIN
dbo.Tool AS Tool ON Map.ToolId = Tool.Id) t1
GROUP BY t1.GroupId, t1.GroupName, t1.Id, t1.Position, t1.Definition, t1.IsEvaluationActive