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

需求:匹配SQL查询区域的正则表达式,拆分区域与对应值

拆分带嵌套子查询的SQL区域关键字内容

要解决这个问题,核心难点是处理括号嵌套的子查询,避免子查询内的同名字段/关键字干扰外层SQL的区域分割。单纯按关键字分割会直接失效,必须结合平衡括号匹配来确保每个区域的内容归属正确。

核心思路

  1. 用正则的平衡组特性处理嵌套括号,确保子查询内部的内容被完整包含在对应区域中,不会提前触发下一个关键字的匹配。
  2. 精准匹配指定的区域关键字(作为完整单词,避免字段名包含关键字的误匹配),并关联其对应的内容直到下一个关键字或SQL结尾。

正则表达式(C#环境)

\b(SELECT|FROM|WHERE|GROUP BY|HAVING|ORDER BY|OFFSET|LIMIT)\b\s*(?(?=\()((?>[^()]+|(?<open>\()|(?<-open>\()))*(?(open)(?!))|.*?)(?=\b(SELECT|FROM|WHERE|GROUP BY|HAVING|ORDER BY|OFFSET|LIMIT)\b|$)

正则解析

  • \b(关键字列表)\b:匹配指定的区域关键字,\b确保是完整单词(比如不会把SELECTION里的SELECT误判为关键字)。
  • \s*:匹配关键字后的任意空白(包括换行、空格)。
  • 条件分支(?(?=\()...|.*?):
    • 如果关键字后紧跟左括号(,则用平衡组匹配所有嵌套括号内容,直到括号完全闭合。
    • 否则,匹配内容直到下一个区域关键字或SQL结尾。
  • 平衡组部分((?>[^()]+|(?<open>\()|(?<-open>\()))*(?(open)(?!)):通过栈式计数匹配嵌套括号,确保只有当括号完全闭合时才停止匹配。

代码实现(C#)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

public class SqlRegionSplitter
{
    public static Dictionary<string, string> SplitSqlIntoRegions(string sql)
    {
        var regionKeywords = new[] { "SELECT", "FROM", "WHERE", "GROUP BY", "HAVING", "ORDER BY", "OFFSET", "LIMIT" };
        var escapedKeywords = string.Join("|", regionKeywords.Select(Regex.Escape));
        var pattern = $@"\b({escapedKeywords})\b\s*(?(?=\()((?>[^()]+|(?<open>\()|(?<-open>\()))*(?(open)(?!))|.*?)(?=\b({escapedKeywords})\b|$)";
        
        var regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
        var matches = regex.Matches(sql);
        var regionDict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        foreach (Match match in matches)
        {
            var regionKey = match.Groups[1].Value.Trim();
            var regionValue = match.Groups[2].Success ? match.Groups[2].Value.Trim() : match.Groups[3].Value.Trim();
            regionDict[regionKey] = regionValue;
        }

        return regionDict;
    }

    // 测试示例
    public static void Main()
    {
        var testSql = @"SELECT id, username
                        FROM (SELECT u.id, u.username FROM users u WHERE u.age >= 18) AS adult_users
                        WHERE adult_users.username LIKE '%dev%'
                        GROUP BY adult_users.id
                        HAVING COUNT(adult_users.id) > 2
                        ORDER BY adult_users.username DESC
                        OFFSET 5
                        LIMIT 10";

        var result = SplitSqlIntoRegions(testSql);
        foreach (var kvp in result)
        {
            Console.WriteLine($"{kvp.Key}: {kvp.Value}");
        }
    }
}

注意事项

  • 该实现依赖C#正则的平衡组特性,Python、JavaScript等语言不支持原生平衡组,需改用递归正则或手动编写括号嵌套处理逻辑。
  • 启用IgnoreCase确保兼容SQL大小写不敏感的写法,Singleline模式让.能匹配换行符,支持跨行的SQL语句。
  • 若SQL存在注释,需先移除注释再进行拆分,否则注释中的关键字会干扰匹配。

内容的提问来源于stack exchange,提问作者JAlvez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 12:22:25