TSQL 如何从记录集动态生成多表关联SELECT查询语句
实现方案
方案1:SQL Server 2017及以上版本(推荐,使用STRING_AGG)
这个版本原生支持字符串聚合函数,逻辑更简洁易读,生成结果和预期完全一致:
SELECT PSchemaName, PTableName, FSchemaName, FTableName, CONCAT( 'SELECT ', -- 拼接所有从表查询字段 STRING_AGG(CONCAT('[F].[', FColumnName, ']'), ', ') WITHIN GROUP (ORDER BY ColumnOrder), ', ', -- 拼接所有主表查询字段 STRING_AGG(CONCAT('[P].[', PColumnName, ']'), ', ') WITHIN GROUP (ORDER BY ColumnOrder), ' FROM [', FSchemaName, '].[', FTableName, '] AS [F] JOIN [', PSchemaName, '].[', PTableName, '] AS [P] ON ', -- 拼接关联条件 STRING_AGG(CONCAT('[P].[', PColumnName, '] = [F].[', FColumnName, ']'), ' AND ') WITHIN GROUP (ORDER BY ColumnOrder), ' ;' ) AS CMD FROM @Tbl_List GROUP BY PSchemaName, PTableName, FSchemaName, FTableName ORDER BY PSchemaName, PTableName, FSchemaName, FTableName
方案2:SQL Server 2016及更低版本(兼容旧版本,使用FOR XML PATH)
如果你使用的是不支持STRING_AGG的旧版本SQL Server,可以用经典的FOR XML拼接方案:
SELECT main.PSchemaName, main.PTableName, main.FSchemaName, main.FTableName, CONCAT( 'SELECT ', -- 拼接所有从表字段 STUFF(( SELECT CONCAT(', [F].[', FColumnName, ']') FROM @Tbl_List sub WHERE sub.PSchemaName = main.PSchemaName AND sub.PTableName = main.PTableName AND sub.FSchemaName = main.FSchemaName AND sub.FTableName = main.FTableName ORDER BY sub.ColumnOrder FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, ''), ', ', -- 拼接所有主表字段 STUFF(( SELECT CONCAT(', [P].[', PColumnName, ']') FROM @Tbl_List sub WHERE sub.PSchemaName = main.PSchemaName AND sub.PTableName = main.PTableName AND sub.FSchemaName = main.FSchemaName AND sub.FTableName = main.FTableName ORDER BY sub.ColumnOrder FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, ''), ' FROM [', main.FSchemaName, '].[', main.FTableName, '] AS [F] JOIN [', main.PSchemaName, '].[', main.PTableName, '] AS [P] ON ', -- 拼接关联条件 STUFF(( SELECT CONCAT(' AND [P].[', PColumnName, '] = [F].[', FColumnName, ']') FROM @Tbl_List sub WHERE sub.PSchemaName = main.PSchemaName AND sub.PTableName = main.PTableName AND sub.FSchemaName = main.FSchemaName AND sub.FTableName = main.FTableName ORDER BY sub.ColumnOrder FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 5, ''), ' ;' ) AS CMD FROM @Tbl_List main GROUP BY main.PSchemaName, main.PTableName, main.FSchemaName, main.FTableName ORDER BY main.PSchemaName, main.PTableName, main.FSchemaName, main.FTableName
实现原理说明
- 拼接
=符号:单条关联规则直接按照[P].[{PColumnName}] = [F].[{FColumnName}]的固定格式拼接即可,每条记录生成一个完整的相等判断条件,不需要额外处理。 - 多条件自动加
AND:- 用
STRING_AGG时直接指定分隔符为AND,聚合函数会自动在多个条件之间插入分隔符,首尾不会产生多余的连接符。 - 用
FOR XML PATH时,子查询返回的每个条件前都拼接AND,最后用STUFF函数删除开头多余的5个字符(也就是第一个多余的AND),即可得到正确的条件串。
- 用
- 顺序控制:两种方案都通过
ColumnOrder字段排序,保证字段选择、关联条件的顺序完全符合要求。
注:你提供的预期输出最后一行存在两处笔误,从表
empdtl4被误写为empdtl3,主表emphdr3被误写为emphdr4,上述代码生成的结果会自动修正该问题。
内容的提问来源于stack exchange,提问作者007
相关产品推荐
相关产品推荐

