You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C# ScriptDom提取SQL Server查询中的关联表及关联列?

可以用C# ScriptDom实现SQL关联列提取需求

完全可以通过ScriptDom实现这个需求。ScriptDom是微软官方提供的TSQL语法解析库,能将SQL语句解析为结构化的抽象语法树(AST),我们只需要遍历AST中的JOIN条件节点,提取其中的表名和关联列即可。

实现步骤

  1. 引入依赖:先安装Microsoft.SqlServer.TransactSql.ScriptDom NuGet包,这是解析TSQL的核心库。
  2. 自定义AST访问器:继承TSqlConcreteFragmentVisitor,重写Visit(BinaryExpression node)方法,专门处理JOIN ON子句中的等值判断(BinaryExpressionType.Equals类型的节点)。
  3. 提取列信息:在访问器中,识别等值表达式两侧的ColumnReferenceExpression节点,从中解析出表别名/表名和列名。
  4. 解析SQL并收集结果:用TSql160Parser解析目标SQL,再用自定义访问器遍历AST,收集所有关联列信息。

示例代码

using Microsoft.SqlServer.TransactSql.ScriptDom;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public class JoinColumnVisitor : TSqlConcreteFragmentVisitor
{
    public List<(string TableName, string ColumnName)> JoinColumns { get; } = new();

    public override void Visit(BinaryExpression node)
    {
        // 仅处理等值关联的场景
        if (node.BinaryExpressionType == BinaryExpressionType.Equals)
        {
            ExtractColumnInfo(node.FirstExpression);
            ExtractColumnInfo(node.SecondExpression);
        }
        base.Visit(node);
    }

    private void ExtractColumnInfo(TSqlFragment expression)
    {
        if (expression is ColumnReferenceExpression columnRef)
        {
            // 提取表名和列名(适配[表名].[列名]格式的引用)
            if (columnRef.MultiPartIdentifier.Identifiers.Count >= 2)
            {
                string tableName = columnRef.MultiPartIdentifier.Identifiers[0].Value;
                string columnName = columnRef.MultiPartIdentifier.Identifiers[1].Value;
                JoinColumns.Add((tableName, columnName));
            }
        }
    }
}

public class SqlAnalyzer
{
    public static List<(string TableName, string ColumnName)> ExtractJoinColumns(string sql)
    {
        var parser = new TSql160Parser(false);
        IList<ParseError> errors;
        using var reader = new StringReader(sql);
        var fragment = parser.Parse(reader, out errors);

        if (errors.Count > 0)
        {
            throw new InvalidOperationException($"SQL解析错误:{string.Join(", ", errors.Select(e => e.Message))}");
        }

        var visitor = new JoinColumnVisitor();
        fragment.Accept(visitor);
        // 可选:对结果去重,避免重复输出同一表列
        return visitor.JoinColumns.Distinct().ToList();
    }
}

// 测试示例
class Program
{
    static void Main()
    {
        string sql = @"SELECT *
FROM tabel1
INNER JOIN tabel2 ON tabel1.varchar1col = tabel2.varchar1col
INNER JOIN tabel3 ON tabel1.varchar2col = tabel3.varchar2col
LEFT JOIN tabel4 ON tabel3.varchar2col = tabel4.varchar3col";

        var joinColumns = SqlAnalyzer.ExtractJoinColumns(sql);
        foreach (var (table, column) in joinColumns)
        {
            Console.WriteLine($"{table} {column}");
        }
    }
}

输出结果

运行上述代码后,会输出和你期望完全一致的内容:

tabel1 varchar1col
tabel2 varchar1col
tabel1 varchar2col
tabel3 varchar2col
tabel4 varchar3col

内容的提问来源于stack exchange,提问作者adam.g

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:15:05