如何利用ScriptDom生成修改列名格式的T-SQL新脚本?
基于Microsoft.SqlServer.TransactSql.ScriptDom修改T-SQL列名格式的实现
需求说明
需要构建T-SQL解析器,生成符合特定规则的新查询:将所有用方括号包裹的列名替换为单引号包裹的形式(例如[B]替换为'B')。已有基于Microsoft.SqlServer.TransactSql.ScriptDom的C#代码用于提取列名,但不知道如何生成修改后的完整T-SQL脚本。
示例:
原SQL语句:
SELECT A,[B],C,[D],E FROM T WHERE isnumeric(col3) = 1 Order by [Id] desc
期望转换后的结果:
SELECT A,'B',C,'D',E FROM T WHERE isnumeric(col3) = 1 Order by 'Id' desc
解决方案
通过自定义TSqlFragmentVisitor遍历抽象语法树(AST),替换目标节点后,使用TSqlScriptGenerator重新生成SQL脚本。具体步骤如下:
- 解析原SQL生成AST结构
- 遍历AST并替换指定格式的列名节点
- 将修改后的AST重新生成为SQL文本
完整代码实现
using System; using System.Collections.Generic; using System.IO; using Microsoft.SqlServer.TransactSql.ScriptDom; namespace TSqlTransformer { public class QueryTransformer { public string Transform(string originalSql) { // 解析原SQL生成AST TSql100Parser parser = new TSql100Parser(false); using TextReader reader = new StringReader(originalSql); if (!parser.Parse(reader, out IList<ParseError> errors, out TSqlFragment fragment)) { throw new InvalidOperationException($"SQL解析错误:{string.Join(", ", errors)}"); } // 遍历AST并修改列名节点 var transformerVisitor = new ColumnNameTransformerVisitor(); fragment.Accept(transformerVisitor); // 生成修改后的SQL脚本 TSql100ScriptGenerator generator = new TSql100ScriptGenerator(); generator.GenerateScript(fragment, out string transformedSql); return transformedSql; } } internal class ColumnNameTransformerVisitor : TSqlConcreteFragmentVisitor { // 处理列引用表达式 public override void Visit(ColumnReferenceExpression node) { // 仅处理单部分列引用(如[B]、Id,排除Schema.Table.Column这类多部分引用) if (node.MultiPartIdentifier.Identifiers.Count == 1) { var identifier = node.MultiPartIdentifier.Identifiers[0]; // 替换带方括号的标识符为单引号包裹的字符串 if (identifier is QuotedIdentifier quotedId) { var stringLiteral = new StringLiteral { Value = quotedId.Value, QuoteType = QuoteType.SingleQuote }; node.MultiPartIdentifier.Identifiers[0] = stringLiteral; } } base.Visit(node); } } class Program { static void Main(string[] args) { string originalSql = "SELECT A,[B],C,[D],E FROM T WHERE isnumeric(col3) = 1 Order by [Id] desc"; QueryTransformer transformer = new QueryTransformer(); string transformedSql = transformer.Transform(originalSql); Console.WriteLine("转换后的SQL:"); Console.WriteLine(transformedSql); } } }
代码说明
- SQL解析:使用
TSql100Parser将原SQL字符串转换为可操作的AST结构 - 节点替换:自定义访问器遍历列引用节点,将带方括号的
QuotedIdentifier替换为单引号包裹的StringLiteral - 脚本生成:通过
TSql100ScriptGenerator将修改后的AST重新转换为标准SQL文本
扩展说明
- 如果需要替换所有列名(包括不带方括号的),可移除对
QuotedIdentifier的类型判断,直接将Identifier转换为StringLiteral - 若要支持多部分列引用(如
dbo.Table.[Column]),可扩展Visit方法中的逻辑,判断并替换指定层级的标识符
内容的提问来源于stack exchange,提问作者adam.g
相关产品推荐
相关产品推荐

