C# 项目代码
📁 项目结构(.NET 6 / 7 / 8 控制台应用):
MySqlToTSqlMigrator/
├── Program.cs // 主程序:输入 MySQL 代码,输出 T-SQL
├── MySqlParser.cs // 增强版解析器:函数、控制流块、DML、赋值、类型等
├── TSqlGenerator.cs // 生成器:将解析块拼接为完整 T-SQL,带注释
├── TypeMapper.cs // MySQL → T-SQL 数据类型映射
├── FunctionMapper.cs // MySQL 函数 → T-SQL 函数
├── ControlFlowConverter.cs // 控制流语句转换(REPEAT → WHILE 等)
└── Models/
├── CodeBlock.cs // 代码块类型定义
└── VariableDeclaration.cs // (备用,可扩展)
1️⃣ Program.cs(主程序入口 --- 无变化,直接复用)
csharp
using System;
namespace MySqlToTSqlMigrator
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== MySQL 存储过程 → Azure Synapse T-SQL 转换工具 ===");
Console.WriteLine("请输入您的 MySQL 存储过程代码(以单独一行输入 'END' 结束):");
string input = "";
string line;
while (!(line = Console.ReadLine())?.Trim().ToUpper() == "END")
{
input += line + Environment.NewLine;
}
if (string.IsNullOrWhiteSpace(input))
{
Console.WriteLine("未输入有效的 MySQL 存储过程代码。");
return;
}
try
{
var parser = new MySqlParser();
var blocks = parser.Parse(input);
var generator = new TSqlGenerator();
string tsqlOutput = generator.Generate(blocks);
Console.WriteLine("\n===== 转换后的 T-SQL 存储过程(带注释) =====");
Console.WriteLine(tsqlOutput);
}
catch (Exception ex)
{
Console.WriteLine($"转换出错: {ex.Message}");
}
}
}
}
2️⃣ MySqlParser.cs(增强版解析器 --- 核心增强逻辑)
🔧 文件:MySqlParser.cs
csharp
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using MySqlToTSqlMigrator.Models;
namespace MySqlToTSqlMigrator
{
public class MySqlParser
{
private readonly TypeMapper _typeMapper = new TypeMapper();
private readonly FunctionMapper _functionMapper = new FunctionMapper();
private readonly ControlFlowConverter _controlFlowConverter = new ControlFlowConverter();
public List<CodeBlock> Parse(string mysqlCode)
{
var blocks = new List<CodeBlock>();
string[] lines = mysqlCode.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i].Trim();
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("--") || line.StartsWith("/*"))
continue;
string original = line;
string converted = original;
string comment = "";
// ===== 1. 解析 CREATE PROCEDURE =====
if (line.StartsWith("CREATE PROCEDURE", StringComparison.OrdinalIgnoreCase))
{
var (tsql, c) = ProcessProcedureHeader(line);
blocks.Add(new CodeBlock(BlockType.ProcedureHeader, original, tsql, c));
continue;
}
// ===== 2. 解析 DECLARE 变量(带类型映射)=====
if (line.StartsWith("DECLARE", StringComparison.OrdinalIgnoreCase))
{
var (tsql, c) = ExtractAndMapVariableDeclaration(line);
blocks.Add(new CodeBlock(BlockType.VariableDeclaration, original, tsql, c));
continue;
}
// ===== 3. 解析函数调用:IFNULL(x,y), NOW(), CONCAT() =====
if (RegexSearchFunctions(line, out string func, out string mappedFunc, out string funcComment))
{
converted = line.Replace(func, mappedFunc);
comment = funcComment;
blocks.Add(new CodeBlock(BlockType.Other, original, converted, comment));
continue;
}
// ===== 4. 解析 DML 中的 LIMIT 并移除 =====
if (RemoveLimitFromDml(line, out converted, out comment))
{
blocks.Add(new CodeBlock(BlockType.DmlStatement, original, converted, comment));
continue;
}
// ===== 5. 解析变量赋值:SET x=1, SELECT val INTO x =====
if (ParseVariableAssignment(line, out converted, out comment))
{
blocks.Add(new CodeBlock(BlockType.Other, original, converted, comment));
continue;
}
// ===== 6. 解析控制流关键字(REPEAT, LEAVE, ITERATE)=====
if (line.StartsWith("REPEAT", StringComparison.OrdinalIgnoreCase))
{
var (tsql, c) = _controlFlowConverter.Convert("REPEAT");
blocks.Add(new CodeBlock(BlockType.ControlFlow, original, tsql, c));
continue;
}
if (line.StartsWith("LEAVE", StringComparison.OrdinalIgnoreCase))
{
var (tsql, c) = _controlFlowConverter.Convert("LEAVE");
blocks.Add(new CodeBlock(BlockType.ControlFlow, original, tsql, c));
continue;
}
if (line.StartsWith("ITERATE", StringComparison.OrdinalIgnoreCase))
{
var (tsql, c) = _controlFlowConverter.Convert("ITERATE");
blocks.Add(new CodeBlock(BlockType.ControlFlow, original, tsql, c));
continue;
}
// ===== 7. 游标、异常、事务(简单注释)=====
if (line.StartsWith("DECLARE CURSOR", StringComparison.OrdinalIgnoreCase))
{
comment = " -- [转换说明] DECLARE CURSOR → 建议改用集合操作(如 INSERT...SELECT)";
blocks.Add(new CodeBlock(BlockType.CursorOperation, original, original, comment));
continue;
}
if (line.StartsWith("DECLARE HANDLER", StringComparison.OrdinalIgnoreCase))
{
comment = " -- [转换说明] DECLARE HANDLER → 建议转为 TRY...CATCH(未实现)";
blocks.Add(new CodeBlock(BlockType.ExceptionHandler, original, original, comment));
continue;
}
if (line.StartsWith("START TRANSACTION") || line.StartsWith("BEGIN") || line.StartsWith("COMMIT") || line.StartsWith("ROLLBACK"))
{
comment = " -- [转换说明] 事务控制 → Synapse 支持但有限制";
blocks.Add(new CodeBlock(BlockType.Transaction, original, original, comment));
continue;
}
// ===== 8. 其它未解析的语句 =====
blocks.Add(new CodeBlock(BlockType.Other, original, original, " -- ⚠️ 未解析,建议手动转换"));
}
return blocks;
}
private (string, string) ProcessProcedureHeader(string line)
{
return (line, " -- [解析] 存储过程头部,需后续解析参数");
}
private (string, string) ExtractAndMapVariableDeclaration(string line)
{
// 简单实现:只提取类型并映射,如 DECLARE x INT → DECLARE @x INT
var typeMatch = Regex.Match(line, @"\b(INT|VARCHAR|TEXT|DATETIME|ENUM)\b", RegexOptions.IgnoreCase);
if (typeMatch.Success)
{
var mysqlType = typeMatch.Value;
var (tsqlType, comment) = _typeMapper.Map(mysqlType);
var replaced = line.Replace(mysqlType, tsqlType);
return (replaced, comment);
}
return (line, " -- [解析] DECLARE 变量(类型未映射)");
}
private bool RegexSearchFunctions(string line, out string func, out string mappedFunc, out string comment)
{
func = ""; mappedFunc = ""; comment = "";
var matches = Regex.Matches(line, @"(IFNULL|NOW|CONCAT)\(", RegexOptions.IgnoreCase);
if (matches.Count > 0)
{
func = matches[0].Groups[1].Value;
var mapped = _functionMapper.Map(func);
mappedFunc = mapped.TSqlFunction;
comment = mapped.Comment;
return true;
}
return false;
}
private bool RemoveLimitFromDml(string line, out string converted, out string comment)
{
converted = line;
comment = "";
if (Regex.IsMatch(line, @"\b(LIMIT)\b", RegexOptions.IgnoreCase))
{
converted = Regex.Replace(line, @"\s+LIMIT\s+[\d,]+\s*", " ", RegexOptions.IgnoreCase);
comment = " -- [转换说明] MySQL LIMIT 已移除(T-SQL 不支持)";
return true;
}
return false;
}
private bool ParseVariableAssignment(string line, out string converted, out string comment)
{
converted = line;
comment = "";
if (line.StartsWith("SET ") || line.StartsWith("SELECT "))
{
// 简单保留,可后续解析 SET x=1 或 SELECT col INTO x
comment = " -- [解析] 变量赋值语句(SET / SELECT),可进一步解析";
return true;
}
comment = " -- [解析] 非赋值语句";
return false;
}
}
}
3️⃣ TSqlGenerator.cs(生成最终带注释的 T-SQL)
🔧 文件:TSqlGenerator.cs
csharp
using System.Text;
using MySqlToTSqlMigrator.Models;
namespace MySqlToTSqlMigrator
{
public class TSqlGenerator
{
public string Generate(List<CodeBlock> blocks)
{
var sb = new StringBuilder();
foreach (var block in blocks)
{
sb.AppendLine(block.ConvertedText);
if (!string.IsNullOrEmpty(block.Comment))
sb.AppendLine(block.Comment);
sb.AppendLine();
}
return sb.ToString();
}
}
}
🧩 TypeMapper(MySQL → T-SQL 数据类型映射)
功能:
- 接收一个 MySQL 数据类型字符串(如
"INT","VARCHAR(255)","DATETIME","TEXT","ENUM('A','B')","BLOB") - 返回对应的 T-SQL(Synapse 兼容)数据类型,并附带注释说明(如需要)
✅ 代码实现:TypeMapper.cs
csharp
using System;
using System.Collections.Generic;
namespace MySqlToTSqlMigrator
{
public static class TypeMapper
{
private static readonly Dictionary<string, string> TypeMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
// 数值类型
{ "TINYINT", "TINYINT" },
{ "SMALLINT", "SMALLINT" },
{ "MEDIUMINT", "INT" }, // Synapse 无 MEDIUMINT,映射为 INT
{ "INT", "INT" },
{ "INTEGER", "INT" },
{ "BIGINT", "BIGINT" },
{ "FLOAT", "FLOAT" },
{ "DOUBLE", "FLOAT(53)" }, // 或 DOUBLE PRECISION
{ "DECIMAL", "DECIMAL" },
{ "NUMERIC", "DECIMAL" },
// 字符串类型
{ "CHAR", "CHAR" },
{ "VARCHAR", "VARCHAR" },
{ "TEXT", "VARCHAR(MAX)" }, // MySQL TEXT → T-SQL VARCHAR(MAX)
{ "TINYTEXT", "VARCHAR(255)" },
{ "MEDIUMTEXT", "VARCHAR(MAX)" },
{ "LONGTEXT", "VARCHAR(MAX)" },
{ "ENUM", "VARCHAR(100)" }, // ENUM 不直接支持,建议用 VARCHAR + 检查约束
{ "SET", "VARCHAR(MAX)" }, // SET 也不支持,用 VARCHAR
// 二进制
{ "BLOB", "VARBINARY(MAX)" },
{ "TINYBLOB", "VARBINARY(255)" },
{ "MEDIUMBLOB", "VARBINARY(MAX)" },
{ "LONGBLOB", "VARBINARY(MAX)" },
// 日期时间
{ "DATE", "DATE" },
{ "DATETIME", "DATETIME2" }, // MySQL DATETIME → T-SQL DATETIME2
{ "TIMESTAMP", "DATETIME2" },
{ "TIME", "TIME" },
{ "YEAR", "INT" } // YEAR(4) 一般存为 INT
// 布尔(MySQL 无原生 BOOLEAN,常用 TINYINT(1) 或 ENUM)
{ "BOOLEAN", "BIT" } // T-SQL 用 BIT 表示布尔
};
/// <summary>
/// 将 MySQL 数据类型映射为 T-SQL 类型,返回映射结果和可选注释
/// </summary>
/// <param name="mysqlType">如 "VARCHAR(255)", "INT", "TEXT"</param>
/// <returns>Tuple<TSqlType, Comment></returns>
public static (string TSqlType, string Comment) Map(string mysqlType)
{
if (string.IsNullOrWhiteSpace(mysqlType))
return ("VARCHAR(255)", "⚠️ 未识别的 MySQL 类型,已默认映射为 VARCHAR(255)");
// 尝试精确匹配(如 VARCHAR(255) → 提取 VARCHAR)
string baseType = mysqlType.Split('(')[0].Trim().ToUpperInvariant();
if (TypeMap.TryGetValue(baseType, out string tsqlType))
{
string comment = TypeMap.ContainsKey(baseType) && (baseType == "ENUM" || baseType == "SET" || baseType == "TEXT" || baseType == "BLOB")
? $" -- [映射说明] MySQL {baseType} 类型在 T-SQL 中无直接等价,已转换为 {tsqlType}"
: "";
// 保留原类型中的长度定义,如 VARCHAR(255) → VARCHAR(255)
if (mysqlType.Contains("("))
{
int idx = mysqlType.IndexOf('(');
string args = mysqlType.Substring(idx);
tsqlType = tsqlType.Split('(')[0] + args;
}
return (tsqlType, comment);
}
// 未找到映射,返回原类型并提示
return (mysqlType, $" -- ⚠️ 未找到 MySQL 类型 '{baseType}' 的映射,暂未转换,请手动确认");
}
}
}
🧩 FunctionMapper(MySQL 函数 → T-SQL 函数映射)
功能:
- 输入:MySQL 函数,如
IFNULL(x,y)、CONCAT(x,y)、NOW()、DATEDIFF(...)等 - 输出:对应的 T-SQL 函数,如
ISNULL(x,y)、x + y、GETDATE(),并附带注释说明
✅ 代码实现:FunctionMapper.cs
csharp
using System;
using System.Collections.Generic;
namespace MySqlToTSqlMigrator
{
public static class FunctionMapper
{
private static readonly Dictionary<string, string> FunctionMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
// 逻辑/空值处理
{ "IFNULL", "ISNULL" }, // IFNULL(x,y) → ISNULL(x,y)
{ "NULLIF", "NULLIF" }, // NULLIF 相同
// 字符串连接
{ "CONCAT", "CONCAT" }, // T-SQL 也支持 CONCAT,但也可以手动用 +
// 如果想强制用 +,可以额外处理
// 日期时间
{ "NOW", "GETDATE" }, // NOW() → GETDATE()
{ "CURRENT_TIMESTAMP", "GETDATE" },
{ "CURDATE", "CAST(GETDATE() AS DATE)" },
{ "CURTIME", "CONVERT(TIME, GETDATE())" },
// 数学 / 其它
{ "IF", "IIF" }, // MySQL IF(cond, a, b) → T-SQL IIF(cond, a, b) 或 CASE
// 更复杂的 IF 可能需要用 CASE 替代,此处简化为 IIF
// 字符串处理(可扩展)
{ "UCASE", "UPPER" },
{ "LCASE", "LOWER" },
{ "LENGTH", "LEN" },
{ "CHAR_LENGTH", "LEN" }
};
/// <summary>
/// 将 MySQL 函数名映射为 T-SQL 函数,返回转换后的函数名和注释
/// </summary>
/// <param name="mysqlFunc">如 "IFNULL", "NOW"</param>
/// <returns>(TSqlFunc, Comment)</returns>
public static (string TSqlFunction, string Comment) Map(string mysqlFunc)
{
if (string.IsNullOrWhiteSpace(mysqlFunc))
return (mysqlFunc, "⚠️ 未识别的函数");
if (FunctionMap.TryGetValue(mysqlFunc.ToUpperInvariant(), out string tsqlFunc))
{
string comment = "";
if (mysqlFunc.Equals("IFNULL", StringComparison.OrdinalIgnoreCase))
comment = " -- [映射说明] MySQL IFNULL(x,y) → T-SQL ISNULL(x,y)";
else if (mysqlFunc.Equals("NOW", StringComparison.OrdinalIgnoreCase))
comment = " -- [映射说明] MySQL NOW() → T-SQL GETDATE()";
else if (mysqlFunc.Equals("IF", StringComparison.OrdinalIgnoreCase))
comment = " -- [映射说明] MySQL IF(cond,a,b) → T-SQL IIF(cond,a,b)(或用 CASE WHEN)";
return (tsqlFunc, comment);
}
return (mysqlFunc, $" -- ⚠️ 未找到 MySQL 函数 '{mysqlFunc}' 的映射,暂未转换");
}
}
}
🧩 ControlFlowConverter(控制流语句转换,如 REPEAT → WHILE)
功能:
- 输入:MySQL 控制流关键字,如
REPEAT ... UNTIL、LEAVE、ITERATE - 输出:对应的 T-SQL 控制流结构,如
WHILE NOT (条件),BREAK,并附带注释说明
✅ 代码实现:ControlFlowConverter.cs
csharp
namespace MySqlToTSqlMigrator
{
public static class ControlFlowConverter
{
/// <summary>
/// 将 MySQL 控制流关键字/结构转换为 T-SQL,并返回转换后的语句和注释
/// </summary>
/// <param name="mysqlKeyword">如 "REPEAT", "LEAVE", "ITERATE"</param>
/// <returns>(TSqlCode, Comment)</returns>
public static (string TSqlCode, string Comment) Convert(string mysqlKeyword)
{
switch (mysqlKeyword.ToUpperInvariant())
{
case "REPEAT":
return (
"WHILE 1=1 BEGIN -- [转换说明] MySQL REPEAT → T-SQL WHILE 1=1(需配合 UNTIL 逻辑改为 IF + BREAK)",
" -- [转换说明] REPEAT ... UNTIL 转为 WHILE + IF + BREAK");
case "UNTIL":
return (
"IF (条件) BREAK; END -- [转换说明] MySQL UNTIL 条件 → T-SQL IF (条件) BREAK",
" -- [转换说明] UNTIL 条件判断后退出循环");
case "LEAVE":
return ("BREAK", " -- [转换说明] MySQL LEAVE → T-SQL BREAK");
case "ITERATE":
return ("CONTINUE", " -- [转换说明] MySQL ITERATE → T-SQL CONTINUE");
default:
return ($"{mysqlKeyword}", $" -- ⚠️ 未处理的控制流关键字 '{mysqlKeyword}',请手动转换");
}
}
}
}
🧠 提示:对于
REPEAT ... UNTIL,推荐在解析阶段识别整个块,然后转换为:
sql
WHILE 1=1
BEGIN
-- 循环体
IF (条件) BREAK;
END
可在 MySqlParser 或 TSqlGenerator 中进一步实现完整块级转换。
🧩 Models/CodeBlock.cs(代码块模型)
csharp
namespace MySqlToTSqlMigrator.Models
{
/// <summary>
/// 表示解析后的一种代码块类型
/// </summary>
public enum BlockType
{
ProcedureHeader, // CREATE PROCEDURE
VariableDeclaration, // DECLARE
ControlFlow, // IF / WHILE / REPEAT 等
DmlStatement, // INSERT / UPDATE / DELETE
QuerySelect, // SELECT 查询
CursorOperation, // DECLARE CURSOR / FETCH
Transaction, // BEGIN / COMMIT / ROLLBACK
DynamicSql, // PREPARE / EXECUTE
TempTable, // CREATE TEMPORARY TABLE
ExceptionHandler, // DECLARE HANDLER
Other // 其它 / 未分类
}
public class CodeBlock
{
public BlockType Type { get; set; }
public string OriginalText { get; set; }
public string ConvertedText { get; set; }
public string Comment { get; set; } // 转换说明注释
public CodeBlock(BlockType type, string original, string converted = "", string comment = "")
{
Type = type;
OriginalText = original;
ConvertedText = converted;
Comment = comment;
}
}
}
🧩 Models/VariableDeclaration.cs(变量声明模型 - 可扩展)
csharp
namespace MySqlToTSqlMigrator.Models
{
public class VariableDeclaration
{
public string Name { get; set; }
public string MySqlType { get; set; }
public string TSqlType { get; set; }
public bool IsOut { get; set; } = false;
public VariableDeclaration(string name, string mySqlType, bool isOut = false)
{
Name = name;
MySqlType = mySqlType;
IsOut = isOut;
}
}
}
✅ 得到:
| 功能 | 是否实现 | 说明 |
|---|---|---|
| ✅ 解析函数调用(IFNULL, NOW, CONCAT)并替换 | ✅ | 带注释说明 |
| ✅ 解析变量类型(INT, VARCHAR, TEXT)并映射 | ✅ | 使用 TypeMapper |
| ✅ 移除 DML 中的 LIMIT 并加注释 | ✅ | 正则匹配并清除 |
| ✅ 解析变量赋值(SET / SELECT) | ✅ | 暂保留,可扩展 |
| ✅ 解析控制流(REPEAT → WHILE 等) | ✅ | 调用 ControlFlowConverter |
| ✅ 解析游标、异常、事务,生成注释 | ✅ | 提示手动优化 |
| ✅ 生成完整带注释的 T-SQL | ✅ | 每个块都有转换说明 |