如何用正则表达式拆分SQL代码为符合SQL Server要求的多执行批次
SQL Server 批处理SQL智能拆分正则方案
核心需求适配
要解决的问题包括:
- 跳过字符串字面量(单引号包裹)中的分号,避免错误拆分
- 将
CREATE PROCEDURE/ALTER PROCEDURE语句单独作为独立批处理(符合SQL Server要求) - 其他常规SQL语句按分号正常拆分
正则表达式实现
(?x) (?:^|;\s*) (?!\s*(CREATE|ALTER)\s+PROCEDURE) (?: (?:[^';]+|'[^']*(?:''[^']*)*')+ ) | \s*(CREATE|ALTER)\s+PROCEDURE\s+[^;]+;?
正则逻辑解释
(?x):开启忽略空白模式,让正则结构更清晰,不影响匹配逻辑(?:^|;\s*):匹配批处理的起始位置——要么是SQL文本开头,要么是分号加任意空白字符(?!\s*(CREATE|ALTER)\s+PROCEDURE):负前瞻断言,确保当前位置不是存储过程定义的开头(?:[^';]+|'[^']*(?:''[^']*)*')+:匹配常规SQL语句内容,处理单引号字符串(包括SQL Server的转义单引号''),跳过字符串内的分号|:分支匹配,专门捕获存储过程定义\s*(CREATE|ALTER)\s+PROCEDURE\s+[^;]+;?:匹配完整的存储过程定义,从关键字开始到末尾分号(允许存储过程末尾无分号)
Java 代码示例
import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.ArrayList; import java.util.List; public class SqlServerBatchSplitter { public static List<String> splitSqlBatches(String sqlContent) { List<String> batches = new ArrayList<>(); String splitRegex = "(?x)(?:^|;\\s*)(?!\\s*(CREATE|ALTER)\\s+PROCEDURE)(?:(?:[^';]+|'[^']*(?:''[^']*)*')+)|\\s*(CREATE|ALTER)\\s+PROCEDURE\\s+[^;]+;?"; Pattern pattern = Pattern.compile(splitRegex); Matcher matcher = pattern.matcher(sqlContent); while (matcher.find()) { String batch = matcher.group().trim(); if (!batch.isEmpty()) { batches.add(batch); } } return batches; } public static void main(String[] args) { String sampleSql = "INSERT INTO Table1 VALUES ('test;1');\nINSERT INTO Table2 VALUES ('abc');\nCREATE PROCEDURE dbo.TestProc\nAS\nBEGIN\n SELECT * FROM Table1;\nEND;\nINSERT INTO Table3 VALUES ('xyz');\nEXEC dbo.TestProc;"; List<String> result = splitSqlBatches(sampleSql); for (int i = 0; i < result.size(); i++) { System.out.printf("=== 批次 %d ===\n%s\n", i+1, result.get(i)); } } }
额外说明
- 该正则已适配SQL Server的单引号转义规则,不会误拆分字符串内的分号
- 存储过程定义内部的分号不会触发拆分,确保存储过程作为单个批处理提交
- 如果需要支持SQL Server常用的
GO批处理分隔符,可以在正则中添加对应分支,比如在起始匹配部分加入(?:^|;\s*|\bGO\b\s*)
内容的提问来源于stack exchange,提问作者Mikhail T.
相关产品推荐
相关产品推荐

