using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Text.Json;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

class SqlServerProcToPySparkConverter
{
    // -------------------------- 配置参数 --------------------------
    private static string _sqlServerName = "localhost"; // SQL Server地址
    private static string _databaseName = "YourDatabase"; // 目标数据库
    private static string _extractedSqlFolder = "./ExtractedProcs"; // 提取的.sql文件保存路径
    private static string _parsedJsonPath = "./ParsedProcs.json"; // 解析结果JSON路径
    private static string _generatedPyPath = "./PySparkProcs.py"; // 生成的PySpark文件路径
    // --------------------------------------------------------------

    static void Main(string[] args)
    {
        Console.WriteLine("===== 开始SQL Server存储过程转PySpark流程 =====");
        
        // 1. 从SQL Server提取存储过程到本地.sql文件
        Console.WriteLine("\n1. 从SQL Server提取存储过程...");
        bool extractSuccess = ExtractProcsFromSqlServer();
        if (!extractSuccess) { Console.WriteLine("提取失败,流程终止"); return; }

        // 2. 解析.sql文件中的存储过程,生成结构化JSON
        Console.WriteLine("\n2. 解析存储过程生成JSON...");
        var allParsedProcs = ParseProcsFromSqlFiles();
        if (allParsedProcs.Count == 0) { Console.WriteLine("无有效存储过程,流程终止"); return; }
        SaveParsedProcsToJson(allParsedProcs);

        // 3. 基于JSON生成PySpark Python文件
        Console.WriteLine("\n3. 生成PySpark代码...");
        bool generateSuccess = GeneratePySparkCode(allParsedProcs);
        if (!generateSuccess) { Console.WriteLine("代码生成失败,流程终止"); return; }

        Console.WriteLine("\n===== 流程完成!生成文件路径:=====");
        Console.WriteLine($"JSON解析结果:{_parsedJsonPath}");
        Console.WriteLine($"PySpark代码:{_generatedPyPath}");
    }

    #region 功能1:从SQL Server提取存储过程(SMO)
    /// <summary>
    /// 使用SMO连接SQL Server,提取非系统存储过程到本地.sql文件
    /// </summary>
    private static bool ExtractProcsFromSqlServer()
    {
        try
        {
            // 创建输出目录
            if (!Directory.Exists(_extractedSqlFolder))
                Directory.CreateDirectory(_extractedSqlFolder);

            // 连接SQL Server
            ServerConnection conn = new ServerConnection(_sqlServerName);
            Server sqlServer = new Server(conn);
            Database targetDb = sqlServer.Databases[_databaseName];

            if (targetDb == null)
            {
                Console.WriteLine($"❌ 未找到数据库:{_databaseName}");
                return false;
            }

            // 提取所有非系统存储过程
            var procs = targetDb.StoredProcedures.Cast<StoredProcedure>()
                .Where(p => !p.IsSystemObject && !string.IsNullOrWhiteSpace(p.TextBody))
                .ToList();

            if (procs.Count == 0)
            {
                Console.WriteLine($"⚠️ 数据库 {_databaseName} 中无有效存储过程");
                return false;
            }

            // 保存每个存储过程到.sql文件
            foreach (var proc in procs)
            {
                string procFullName = $"{proc.Schema}.{proc.Name}";
                string sqlFilePath = Path.Combine(_extractedSqlFolder, $"{proc.Schema}_{proc.Name}.sql");
                File.WriteAllText(sqlFilePath, proc.TextBody);
                Console.WriteLine($"✅ 提取:{procFullName} → {sqlFilePath}");
            }

            Console.WriteLine($"✅ 共提取 {procs.Count} 个存储过程");
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"❌ 提取异常:{ex.Message}");
            return false;
        }
    }
    #endregion

    #region 功能2:解析.sql文件生成结构化数据
    /// <summary>
    /// 读取提取的.sql文件,解析存储过程结构
    /// </summary>
    private static List<dynamic> ParseProcsFromSqlFiles()
    {
        var allParsedProcs = new List<dynamic>();
        var sqlFiles = Directory.GetFiles(_extractedSqlFolder, "*.sql");

        if (sqlFiles.Length == 0)
        {
            Console.WriteLine($"⚠️ {_extractedSqlFolder} 目录下无.sql文件");
            return allParsedProcs;
        }

        foreach (var sqlFile in sqlFiles)
        {
            Console.WriteLine($"🔍 解析文件:{Path.GetFileName(sqlFile)}");
            string sqlContent = File.ReadAllText(sqlFile);
            var procBlocks = ExtractProcedureBlocks(sqlContent);

            foreach (var block in procBlocks)
            {
                var parsedProc = ParseSingleProcedure(block);
                allParsedProcs.Add(parsedProc);
                Console.WriteLine($"   ✅ 解析完成:{parsedProc.ProcedureName}");
            }
        }

        return allParsedProcs;
    }

    /// <summary>
    /// 提取单个.sql文件中的所有CREATE PROCEDURE块
    /// </summary>
    private static List<string> ExtractProcedureBlocks(string sqlContent)
    {
        var blocks = new List<string>();
        var regex = new Regex(
            @"CREATE\s+PROCEDURE\s+([\w\.]+)\s*([\s\S]*?)AS\s+BEGIN\s*([\s\S]*?)END\s*;",
            RegexOptions.IgnoreCase | RegexOptions.Singleline);

        foreach (Match m in regex.Matches(sqlContent))
        {
            if (m.Groups.Count >= 4)
            {
                string fullProcText = $"CREATE PROCEDURE {m.Groups[1].Value} {m.Groups[2].Value} AS BEGIN {m.Groups[3].Value} END;";
                blocks.Add(fullProcText);
            }
        }
        return blocks;
    }

    /// <summary>
    /// 解析单个存储过程的完整结构(参数、变量、查询等)
    /// </summary>
    private static dynamic ParseSingleProcedure(string procText)
    {
        // 提取基础信息
        string procName = ExtractProcedureName(procText);
        var parameters = ParseParameters(procText);
        var variables = ParseVariables(procText);
        var queries = ParseSelectQueries(procText);
        var dml = ParseDmlStatements(procText);
        var tempTables = ParseTempTables(procText);
        var tryCatch = ParseTryCatch(procText);
        var cursors = ParseCursors(procText);
        var dynamicSql = ParseDynamicSql(procText);
        bool hasResultSet = HasSelectResultSet(procText);

        // 整合结构化结果
        return new
        {
            ProcedureName = procName,
            RawText = procText,
            Parameters = parameters,
            Variables = variables,
            SelectQueries = queries,
            DmlStatements = dml,
            TempTables = tempTables,
            TryCatchBlocks = tryCatch,
            Cursors = cursors,
            DynamicSql = dynamicSql,
            HasResultSet = hasResultSet
        };
    }

    // -------------------------- 解析子模块 --------------------------
    private static string ExtractProcedureName(string procText)
    {
        var match = Regex.Match(procText, @"CREATE\s+PROCEDURE\s+([\w\.]+)", RegexOptions.IgnoreCase);
        return match.Success ? match.Groups[1].Value : "UnknownProc";
    }

    private static dynamic ParseParameters(string procText)
    {
        var input = new List<string>();
        var output = new List<string>();
        var regex = new Regex(@"@(\w+)\s+([\w\(\)]+)\s*(OUTPUT)?", RegexOptions.IgnoreCase);

        foreach (Match m in regex.Matches(procText))
        {
            string param = $"@{m.Groups[1].Value} ({m.Groups[2].Value})";
            if (m.Groups[3].Success) output.Add(param);
            else input.Add(param);
        }
        return new { Input = input, Output = output };
    }

    private static List<dynamic> ParseVariables(string procText)
    {
        var vars = new List<dynamic>();
        var regex = new Regex(@"DECLARE\s+@(\w+)\s+([\w\(\)]+)(?:\s*=\s*([^;]+))?", RegexOptions.IgnoreCase);

        foreach (Match m in regex.Matches(procText))
        {
            vars.Add(new
            {
                Name = $"@{m.Groups[1].Value}",
                Type = m.Groups[2].Value,
                InitialValue = m.Groups[3]?.Value ?? "NULL"
            });
        }
        return vars;
    }

    private static List<dynamic> ParseSelectQueries(string procText)
    {
        var queries = new List<dynamic>();
        var regex = new Regex(@"SELECT\s+([\s\S]*?)\s+FROM\s+([\s\S]*?)(?:WHERE\s+([\s\S]*?))?(?:GROUP\s+BY\s+([\s\S]*?))?(?:ORDER\s+BY\s+([\s\S]*?))?;", RegexOptions.IgnoreCase);

        foreach (Match m in regex.Matches(procText))
        {
            queries.Add(new
            {
                Fields = m.Groups[1].Value.Trim(),
                From = m.Groups[2].Value.Trim(),
                Where = m.Groups[3]?.Value?.Trim() ?? "",
                GroupBy = m.Groups[4]?.Value?.Trim() ?? "",
                OrderBy = m.Groups[5]?.Value?.Trim() ?? ""
            });
        }
        return queries;
    }

    private static List<string> ParseDmlStatements(string procText)
    {
        var dml = new List<string>();
        dml.AddRange(Regex.Matches(procText, @"INSERT\s+[\s\S]*?;", RegexOptions.IgnoreCase).Cast<Match>().Select(m => m.Value));
        dml.AddRange(Regex.Matches(procText, @"UPDATE\s+[\s\S]*?;", RegexOptions.IgnoreCase).Cast<Match>().Select(m => m.Value));
        dml.AddRange(Regex.Matches(procText, @"DELETE\s+[\s\S]*?;", RegexOptions.IgnoreCase).Cast<Match>().Select(m => m.Value));
        return dml;
    }

    private static List<dynamic> ParseTempTables(string procText)
    {
        var temps = new List<dynamic>();
        var regex = new Regex(@"CREATE\s+TABLE\s+#(\w+)\s*\(([\s\S]*?)\)", RegexOptions.IgnoreCase);

        foreach (Match m in regex.Matches(procText))
        {
            temps.Add(new
            {
                Name = $"#{m.Groups[1].Value}",
                Columns = m.Groups[2].Value.Trim()
            });
        }
        return temps;
    }

    private static List<dynamic> ParseTryCatch(string procText)
    {
        var tryCatch = new List<dynamic>();
        var tryRegex = new Regex(@"BEGIN\s+TRY\s*([\s\S]*?)\s*END\s+TRY", RegexOptions.IgnoreCase);
        var catchRegex = new Regex(@"BEGIN\s+CATCH\s*([\s\S]*?)\s*END\s+CATCH", RegexOptions.IgnoreCase);

        var tryBlocks = tryRegex.Matches(procText);
        var catchBlocks = catchRegex.Matches(procText);

        for (int i = 0; i < Math.Min(tryBlocks.Count, catchBlocks.Count); i++)
        {
            tryCatch.Add(new
            {
                TryBlock = tryBlocks[i].Groups[1].Value.Trim(),
                CatchBlock = catchBlocks[i].Groups[1].Value.Trim()
            });
        }
        return tryCatch;
    }

    private static List<dynamic> ParseCursors(string procText)
    {
        var cursors = new List<dynamic>();
        var regex = new Regex(@"DECLARE\s+(\w+)\s+CURSOR\s+FOR\s+([\s\S]*?);", RegexOptions.IgnoreCase);

        foreach (Match m in regex.Matches(procText))
        {
            cursors.Add(new
            {
                Name = m.Groups[1].Value,
                Query = m.Groups[2].Value.Trim(),
                PySparkNote = "使用DataFrame.filter/map替代游标逐行逻辑"
            });
        }
        return cursors;
    }

    private static List<string> ParseDynamicSql(string procText)
    {
        return Regex.Matches(procText, @"EXEC\s+sp_executesql\s+[\s\S]*?;", RegexOptions.IgnoreCase)
            .Cast<Match>().Select(m => m.Value).ToList();
    }

    private static bool HasSelectResultSet(string procText)
    {
        return Regex.IsMatch(procText, @"SELECT\s+[^@]", RegexOptions.IgnoreCase); // 排除变量赋值的SELECT
    }

    /// <summary>
    /// 保存解析结果到JSON文件
    /// </summary>
    private static void SaveParsedProcsToJson(List<dynamic> parsedProcs)
    {
        string json = JsonSerializer.Serialize(parsedProcs, new JsonSerializerOptions { WriteIndented = true });
        File.WriteAllText(_parsedJsonPath, json);
        Console.WriteLine($"✅ JSON已保存到:{_parsedJsonPath}");
    }
    #endregion

    #region 功能3:生成PySpark代码
    /// <summary>
    /// 基于解析的存储过程结构,生成PySpark函数代码
    /// </summary>
    private static bool GeneratePySparkCode(List<dynamic> parsedProcs)
    {
        try
        {
            // 构建PySpark代码模板
            var pyBuilder = new System.Text.StringBuilder();
            pyBuilder.AppendLine("\"\"\"");
            pyBuilder.AppendLine($"自动生成的SQL Server存储过程转PySpark代码");
            pyBuilder.AppendLine($"生成时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            pyBuilder.AppendLine($"包含存储过程数量:{parsedProcs.Count}");
            pyBuilder.AppendLine("\"\"\"");
            pyBuilder.AppendLine("from pyspark.sql import SparkSession");
            pyBuilder.AppendLine("from pyspark.sql.functions import col, lit, expr, when");
            pyBuilder.AppendLine("from pyspark.sql.types import *");
            pyBuilder.AppendLine("import logging");
            pyBuilder.AppendLine();
            pyBuilder.AppendLine("# 初始化SparkSession(可根据实际场景调整)");
            pyBuilder.AppendLine("def init_spark(app_name: str = \"ProcToPySpark\") -> SparkSession:");
            pyBuilder.AppendLine("    return SparkSession.builder.appName(app_name).getOrCreate()");
            pyBuilder.AppendLine();

            // 为每个存储过程生成一个PySpark函数
            foreach (var proc in parsedProcs)
            {
                string procName = proc.ProcedureName.Replace(".", "_"); // 处理架构名(如dbo.Proc1→dbo_Proc1)
                var inputParams = proc.Parameters.Input.Select(p => 
                {
                    string paramName = Regex.Match(p, @"@(\w+)").Groups[1].Value;
                    return $"{paramName}: str | int | float = None"; // 简化参数类型
                });

                // 1. 函数签名
                pyBuilder.AppendLine($"def {procName}(");
                pyBuilder.AppendLine($"    spark: SparkSession,");
                pyBuilder.AppendLine($"    {string.Join(",\n    ", inputParams)},");
                pyBuilder.AppendLine($"    logger: logging.Logger = None");
                pyBuilder.AppendLine($") -> dict | None:");
                pyBuilder.AppendLine($"    \"\"\"");
                pyBuilder.AppendLine($"    对应SQL Server存储过程:{proc.ProcedureName}");
                pyBuilder.AppendLine($"    返回值:包含结果集(DataFrame)或执行状态的字典");
                pyBuilder.AppendLine($"    \"\"\"");
                pyBuilder.AppendLine($"    if logger is None:");
                pyBuilder.AppendLine($"        logger = logging.getLogger(__name__)");
                pyBuilder.AppendLine();

                // 2. 变量定义(映射T-SQL局部变量)
                if (proc.Variables.Count > 0)
                {
                    pyBuilder.AppendLine($"    # 局部变量定义(映射T-SQL变量)");
                    foreach (var var in proc.Variables)
                    {
                        string pyVarName = var.Name.Substring(1); // 去掉@符号
string initValue = var.InitialValue.Equals("NULL", StringComparison.OrdinalIgnoreCase) ? "None" : var.InitialValue;
pyBuilder.AppendLine($"    {pyVarName} = {initValue}  # T-SQL类型:{var.Type}");
}
pyBuilder.AppendLine();
}
 
// 3. 临时表处理(映射为Spark临时视图或DataFrame)
if (proc.TempTables.Count > 0)
{
pyBuilder.AppendLine($"    # 临时表处理(映射Spark临时视图)");
foreach (var temp in proc.TempTables)
{
string tempViewName = temp.Name.Substring(1); // 去掉#符号
pyBuilder.AppendLine($"    # T-SQL临时表:{temp.Name}");
pyBuilder.AppendLine($"    # 列定义:{temp.Columns}");
pyBuilder.AppendLine($"    # 方案:1. 从查询创建 | 2. 定义Schema后插入");
pyBuilder.AppendLine($"    # {tempViewName}_schema = StructType([");
pyBuilder.AppendLine($"    #     # 示例:StructField("col1", IntegerType(), nullable=True)");
pyBuilder.AppendLine($"    # ])");
pyBuilder.AppendLine($"    # {tempViewName}_df = spark.createDataFrame([], schema={tempViewName}_schema)");
pyBuilder.AppendLine($"    # {tempViewName}_df.createOrReplaceTempView("{tempViewName}")");
pyBuilder.AppendLine();
}
}
 
// 4. 游标处理(提示用DataFrame集合操作替代)
if (proc.Cursors.Count > 0)
{
pyBuilder.AppendLine($"    # 游标处理(PySpark推荐用集合操作替代逐行逻辑)");
foreach (var cursor in proc.Cursors)
{
pyBuilder.AppendLine($"    # T-SQL游标:{cursor.Name},查询:{cursor.Query.Substring(0, Math.Min(50, cursor.Query.Length))}...");
pyBuilder.AppendLine($"    # 替代方案:直接执行查询生成DataFrame,用filter/map/groupBy等操作处理");
pyBuilder.AppendLine($"    # cursor_df = spark.sql("{cursor.Query.Replace(""", "\"")}")");
pyBuilder.AppendLine($"    # 后续逻辑:cursor_df = cursor_df.filter(...).withColumn(...)");
pyBuilder.AppendLine();
}
}
 
// 5. 核心查询逻辑(映射SELECT为DataFrame/SQL)
if (proc.SelectQueries.Count > 0)
{
pyBuilder.AppendLine($"    # 核心查询逻辑(T-SQL SELECT → PySpark DataFrame)");
for (int i = 0; i < proc.SelectQueries.Count; i++)
{
var query = proc.SelectQueries[i];
string dfName = $"result_df_{i + 1}";
pyBuilder.AppendLine($"    # 查询{i + 1}:提取字段={query.Fields}, 来源={query.From}");
 
// 构建Spark SQL语句
string sparkSql = $"SELECT {query.Fields} FROM {query.From}";
if (!string.IsNullOrWhiteSpace(query.Where)) sparkSql += $" WHERE {query.Where}";
if (!string.IsNullOrWhiteSpace(query.GroupBy)) sparkSql += $" GROUP BY {query.GroupBy}";
if (!string.IsNullOrWhiteSpace(query.OrderBy)) sparkSql += $" ORDER BY {query.OrderBy}";
 
pyBuilder.AppendLine($"    {dfName} = spark.sql("{sparkSql.Replace(""", "\"")}")");
pyBuilder.AppendLine($"    logger.info(f"查询{i + 1}执行完成,返回行数:{dfName}.count()")");
pyBuilder.AppendLine();
}
}
 
// 6. DML操作(映射INSERT/UPDATE/DELETE为Spark操作)
if (proc.DmlStatements.Count > 0)
{
pyBuilder.AppendLine($"    # DML操作(T-SQL → PySpark)");
foreach (var dml in proc.DmlStatements)
{
if (dml.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
{
pyBuilder.AppendLine($"    # INSERT操作:{dml.Substring(0, Math.Min(60, dml.Length))}...");
pyBuilder.AppendLine($"    # 方案:1. 用df.write.saveAsTable(...) | 2. 执行Spark SQL INSERT");
pyBuilder.AppendLine($"    # spark.sql("{dml.Replace(""", "\"")}")");
}
else if (dml.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase))
{
pyBuilder.AppendLine($"    # UPDATE操作:{dml.Substring(0, Math.Min(60, dml.Length))}...");
pyBuilder.AppendLine($"    # 方案:用withColumn更新字段后覆盖写入(注意分区表逻辑)");
pyBuilder.AppendLine($"    # update_df = spark.table("表名").withColumn("列名", 新值).filter("条件")");
pyBuilder.AppendLine($"    # update_df.write.mode("overwrite").saveAsTable("表名")");
}
else if (dml.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
{
pyBuilder.AppendLine($"    # DELETE操作:{dml.Substring(0, Math.Min(60, dml.Length))}...");
pyBuilder.AppendLine($"    # 方案:筛选保留数据后覆盖写入(避免全表删除)");
pyBuilder.AppendLine($"    # keep_df = spark.table("表名").filter("NOT 删除条件")");
pyBuilder.AppendLine($"    # keep_df.write.mode("overwrite").saveAsTable("表名")");
}
pyBuilder.AppendLine();
}
}
 
// 7. 异常处理(映射TRY/CATCH为Python try/except)
if (proc.TryCatchBlocks.Count > 0)
{
pyBuilder.AppendLine($"    # 异常处理(映射T-SQL TRY/CATCH)");
pyBuilder.AppendLine($"    try:");
pyBuilder.AppendLine($"        # TRY块逻辑(已整合到上方查询/DML中)");
pyBuilder.AppendLine($"        pass");
pyBuilder.AppendLine($"    except Exception as e:");
pyBuilder.AppendLine($"        logger.error(f"执行存储过程{proc.ProcedureName}失败:{str(e)}")");
pyBuilder.AppendLine($"        # 可选:添加回滚逻辑(如删除临时视图)");
pyBuilder.AppendLine($"        # spark.catalog.dropTempView("临时视图名")");
pyBuilder.AppendLine($"        raise  # 根据实际需求决定是否抛出异常");
pyBuilder.AppendLine();
}
 
// 8. 结果返回(根据是否有结果集返回DataFrame或状态)
pyBuilder.AppendLine($"    # 结果返回");
if (proc.HasResultSet)
{
pyBuilder.AppendLine($"    # 有结果集:返回最后一个DataFrame或结果字典");
pyBuilder.AppendLine($"    return {{");
pyBuilder.AppendLine($"        "procedure_name": "{proc.ProcedureName}",");
pyBuilder.AppendLine($"        "status": "success",");
pyBuilder.AppendLine($"        "last_result_df": {dfName if proc.SelectQueries.Count > 0 else "None"}");
pyBuilder.AppendLine($"    }}");
}
else
{
pyBuilder.AppendLine($"    # 无结果集:返回执行状态");
pyBuilder.AppendLine($"    return {{");
pyBuilder.AppendLine($"        "procedure_name": "{proc.ProcedureName}",");
pyBuilder.AppendLine($"        "status": "success",");
pyBuilder.AppendLine($"        "message": "DML操作执行完成"");
pyBuilder.AppendLine($"    }}");
}
pyBuilder.AppendLine();
pyBuilder.AppendLine();
}
 
// 9. 测试调用示例
pyBuilder.AppendLine("# -------------------------- 测试调用示例 --------------------------");
pyBuilder.AppendLine("if name == "main":");
pyBuilder.AppendLine("    # 初始化日志和Spark");
pyBuilder.AppendLine("    logging.basicConfig(level=logging.INFO)");
pyBuilder.AppendLine("    spark = init_spark()");
pyBuilder.AppendLine("    logger = logging.getLogger(name)");
pyBuilder.AppendLine();
if (parsedProcs.Count > 0)
{
string testProcName = parsedProcs[0].ProcedureName.Replace(".", "_");
var testParams = parsedProcs[0].Parameters.Input.Select(p =>
{
string paramName = Regex.Match(p, @"@(\w+)").Groups[1].Value;
return $"{paramName}=123"; // 示例参数值
});
pyBuilder.AppendLine($"    # 调用第一个存储过程示例");
pyBuilder.AppendLine($"    result = {testProcName}(spark, {string.Join(", ", testParams)}, logger)");
pyBuilder.AppendLine($"    logger.info(f"调用结果:{result}")");
}
pyBuilder.AppendLine("    spark.stop()");
 
// 保存PySpark代码到文件
File.WriteAllText(_generatedPyPath, pyBuilder.ToString());
return true;
}
catch (Exception ex)
{
Console.WriteLine($"❌ 生成PySpark代码异常:{ex.Message}");
return false;
}
}
#endregion
}

关键说明与使用步骤

  1. 环境准备

    • 安装 .NET 6+ SDK(支持 C# 10+)
    • 安装 SMO NuGet 包:dotnet add package Microsoft.SqlServer.SqlManagementObjects
    • 确保目标机器可访问 SQL Server(开放 1433 端口,具备 VIEW DEFINITION 权限)
  2. 配置修改

    • 找到代码中 配置参数 区域,修改:
      • _sqlServerName:SQL Server 地址(如 localhost192.168.1.100\SQLEXPRESS
      • _databaseName:需要提取存储过程的数据库名(如 SalesDB
      • 输出路径(_extractedSqlFolder/_parsedJsonPath/_generatedPyPath)可按需调整
  3. 运行流程

    1. 执行程序后,自动连接 SQL Server 提取非系统存储过程,保存为 .sql 文件到 ./ExtractedProcs
    2. 解析所有 .sql 文件,生成包含存储过程结构的 JSON(ParsedProcs.json
    3. 基于 JSON 生成 PySpark 代码(PySparkProcs.py),包含:
      • 每个存储过程对应的 PySpark 函数
      • 变量/临时表/游标/DML 的等效实现方案
      • 异常处理与日志记录
      • 测试调用示例

生成的 PySpark 代码特点

  • 兼容性:适配 PySpark 3.x,使用 DataFrame API + Spark SQL 混合实现
  • 可扩展性:每个模块(变量/查询/DML)都有注释说明,支持根据实际业务调整逻辑
  • 安全性:避免动态 SQL 风险,推荐用参数化查询替代 sp_executesql
  • 易用性:包含 init_spark 工具函数和测试调用示例,开箱即用。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐