You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Python正则表达式提取文本中所有多行SQL SELECT语句块?

解决SQL SELECT语句块提取的正则问题

首先,你的问题核心卡在两个点上:正则默认不支持跨行匹配,加上贪婪匹配的逻辑错误,导致要么只能抓固定行数,要么直接匹配不到结果。咱们一步步来搞定它:

问题根源拆解

你之前用的\(?select.*(\n.*)*[;\)]没结果,主要原因是:

  • 正则里的.默认不匹配换行符,所以.*只能扫单行内容,跨行的语句直接被忽略;
  • 就算加了(\n.*)*,没启用跨行匹配标志的话,还是没法识别换行后的内容;
  • 贪婪模式的.*会尽可能匹配最长内容,很容易把多个SELECT语句合并成一个结果,反而漏掉目标块。

修正后的正则方案

试试这个配合跨行标志的非贪婪正则,能适配任意行数的SELECT语句,包括带括号的子查询:

import re

sql_que = """ select p.value_n, p.enabled from proper p; select p.value_n, p.enabled from proper p where p.property_name = 'PROP1'; (select p.value_n, p.enabled from proper p where p.property_name = 'PROP1' union all select p.value_n, p.enabled from proper p where p.property_name = 'PROP2' )"""

# 适配任意行数的SELECT匹配正则
pattern = r'\(?select.*?[;\)]'
# 启用DOTALL让.匹配换行,IGNORECASE兼容大小写的SELECT
matches = re.findall(pattern, sql_que, re.DOTALL | re.IGNORECASE)

# 输出匹配结果
for idx, match in enumerate(matches, 1):
    print(f"匹配到的SELECT语句块 {idx}:\n{match.strip()}\n")

正则各部分说明

  • \(?:匹配可选的开头括号,兼容子查询场景;
  • select:匹配SELECT关键字(加IGNORECASE可以处理大小写混合的情况);
  • .*?非贪婪匹配任意字符(包括换行,因为有DOTALL),直到遇到最近的结束符;
  • [;\)]:匹配语句结束标记,分号或者闭合括号。

运行这段代码后,你会得到三个正确的SELECT块:

  1. select p.value_n, p.enabled from proper p;
  2. select p.value_n, p.enabled from proper p where p.property_name = 'PROP1';
  3. (select p.value_n, p.enabled from proper p where p.property_name = 'PROP1' union all select p.value_n, p.enabled from proper p where p.property_name = 'PROP2' )

复杂场景的更优方案:用SQL解析库

如果你的SQL涉及多层嵌套括号、注释、复杂语法,正则很容易失效。这时候推荐用专门的SQL解析库sqlparse,能更可靠地处理各种SQL结构:

首先安装库:

pip install sqlparse

然后用代码提取SELECT语句:

import sqlparse

sql_que = """ select p.value_n, p.enabled from proper p; select p.value_n, p.enabled from proper p where p.property_name = 'PROP1'; (select p.value_n, p.enabled from proper p where p.property_name = 'PROP1' union all select p.value_n, p.enabled from proper p where p.property_name = 'PROP2' )"""

# 解析SQL内容
parsed = sqlparse.parse(sql_que)

# 筛选所有SELECT语句
select_statements = []
for stmt in parsed:
    if stmt.get_type() == 'SELECT':
        # 格式化语句,让输出更整洁
        select_statements.append(sqlparse.format(stmt.to_unicode(), reindent=True))

# 输出结果
for idx, stmt in enumerate(select_statements, 1):
    print(f"提取到的SELECT语句 {idx}:\n{stmt}\n")

这个方法能完美处理嵌套子查询、复杂语法,比正则更稳定。

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

火山引擎 最新活动