SQL Server:无需子查询实现多行合并为单行的方法
嘿,我来帮你搞定这个问题!你原来用子查询实现了把每个Declaration对应的Conflicts Title拼接成逗号分隔的字符串,但因为要创建带全文索引的视图,嵌套子查询的视图不符合索引要求对吧?别担心,这里有两种可行的方案,都不需要子查询,还能满足创建可索引视图的条件:
解决方案:无嵌套子查询的字符串聚合 + 可索引视图
方法1:用STRING_AGG(SQL Server 2017+ 优先推荐)
SQL Server 2017及以上版本提供了原生的STRING_AGG函数,专门用来做字符串聚合,语法简洁,性能也更好,完全不需要子查询,非常适合用来创建可索引视图。
第一步:创建绑定架构的视图
CREATE VIEW dbo.DeclarationConflictsAggregated WITH SCHEMABINDING AS SELECT dd.Id, STRING_AGG(cc.Title, ',') AS ConflictTitles, COUNT_BIG(*) AS RowCount -- 索引视图必须包含COUNT_BIG函数,这是硬性要求 FROM dbo.Declarations dd LEFT JOIN dbo.Conflicts cc ON cc.DeclarationId = dd.Id GROUP BY dd.Id GO
第二步:创建唯一聚集索引
要给视图建索引,必须先创建唯一聚集索引,这是前提:
CREATE UNIQUE CLUSTERED INDEX IX_DeclarationConflictsAggregated_Id ON dbo.DeclarationConflictsAggregated(Id) GO
第三步:创建全文索引
现在这个视图没有嵌套子查询,且满足索引视图的所有要求,你可以直接给它创建全文索引了。
方法2:兼容低版本SQL Server(2016及以下)
如果你的SQL Server版本还没到2017,没法用STRING_AGG,可以用FOR XML PATH结合GROUP BY的方式替代,同样能避免嵌套子查询:
第一步:创建绑定架构的视图
如果想要和你原来的结果完全一致(开头带逗号,结尾也可能带逗号),可以用这个写法:
CREATE VIEW dbo.DeclarationConflictsAggregated WITH SCHEMABINDING AS SELECT dd.Id, ( SELECT ',' + cc.Title FROM dbo.Conflicts cc WHERE cc.DeclarationId = dd.Id FOR XML PATH('') ) AS ConflictTitles, COUNT_BIG(*) AS RowCount FROM dbo.Declarations dd LEFT JOIN dbo.Conflicts cc ON cc.DeclarationId = dd.Id GROUP BY dd.Id GO
如果想去掉开头多余的逗号,就用STUFF函数处理一下:
CREATE VIEW dbo.DeclarationConflictsAggregated WITH SCHEMABINDING AS SELECT dd.Id, STUFF( ( SELECT ',' + cc.Title FROM dbo.Conflicts cc WHERE cc.DeclarationId = dd.Id FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 1, '' ) AS ConflictTitles, COUNT_BIG(*) AS RowCount FROM dbo.Declarations dd LEFT JOIN dbo.Conflicts cc ON cc.DeclarationId = dd.Id GROUP BY dd.Id GO
第二步:创建唯一聚集索引
同样需要先创建唯一聚集索引:
CREATE UNIQUE CLUSTERED INDEX IX_DeclarationConflictsAggregated_Id ON dbo.DeclarationConflictsAggregated(Id) GO
重要提醒
- 索引视图必须满足几个硬性条件:必须带
WITH SCHEMABINDING、必须包含COUNT_BIG函数、必须先创建唯一聚集索引才能创建其他索引(包括全文索引)。 - 能用
STRING_AGG的话就优先用,它的性能和可读性都比FOR XML PATH的写法好很多。
内容的提问来源于stack exchange,提问作者user1167761
相关产品推荐
相关产品推荐

