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

如何用Python re模块检测Oracle存储过程与函数中的表名

Improved Approach to Extract Table Names from Oracle Stored Procedures/Functions with Python re

Great question! Your initial regex is a solid starting point, but it falls short of handling all the Oracle FROM clause variations you listed—like JOIN syntax, schema-qualified tables, quoted identifiers, and multi-table comma-separated joins. Let's break down a more robust solution step by step.

1. First: Address Limitations of Your Current Code

Your current pattern FROM \w+ \w* [WHERE|,|;]* has a few key gaps:

  • It doesn't account for schema-qualified tables (e.g., SCOTT.EMP)
  • It can't handle quoted table names (Oracle allows double-quoted identifiers like "EMP_TABLE")
  • It misses tables referenced in JOIN clauses (e.g., FROM EMP e JOIN DEPT d ON e.DEPTNO = d.DEPTNO)
  • It doesn't ignore comments (you might accidentally match FROM in -- FROM test_table or /* FROM test_table */)

2. Step-by-Step Robust Regex Design

Let's build a regex that covers all your required cases, plus common Oracle edge cases:

a. Define Valid Oracle Identifiers

Oracle table names can take three forms, so we need a pattern that matches all:

  • Plain identifiers: Start with a letter, followed by letters, numbers, or underscores
  • Schema-qualified: schema.table
  • Quoted: "My-Table-With-Special-Chars"

We can represent this with:

(?:(?:"[^"]+")|(?:[A-Za-z_][A-Za-z0-9_]*\.)?[A-Za-z_][A-Za-z0-9_]*)
  • (?:"[^"]+"): Matches quoted identifiers
  • (?:[A-Za-z_][A-Za-z0-9_]*\.)?: Optional schema prefix
  • [A-Za-z_][A-Za-z0-9_]*: Plain identifier

b. Match FROM and JOIN Table References

We need to capture tables from both the initial FROM clause and any subsequent JOIN (INNER/LEFT/RIGHT/FULL) clauses. The full pattern (case-insensitive, allows whitespace/newlines) looks like:

(?:FROM|JOIN)\s+(?P<table>(?:(?:"[^"]+")|(?:[A-Za-z_][A-Za-z0-9_]*\.)?[A-Za-z_][A-Za-z0-9_]*))(?:\s+(?P<alias>(?:"[^"]+")|[A-Za-z_][A-Za-z0-9_]*))?

c. Preprocess: Remove Comments First

Before running the regex, strip Oracle-style comments to avoid false matches:

  • Line comments: -- ... until the end of the line
  • Block comments: /* ... */ (can span multiple lines)

3. Full Python Implementation

Here's a complete function that handles all these cases:

import re

def extract_oracle_table_names(procedure_code):
    # Step 1: Remove block comments /* ... */
    code_no_block_comments = re.sub(r'/\*.*?\*/', '', procedure_code, flags=re.DOTALL)
    # Step 2: Remove line comments -- ...
    code_no_comments = re.sub(r'--.*$', '', code_no_block_comments, flags=re.MULTILINE)
    
    # Step 3: Regex to match FROM/JOIN table references
    table_pattern = re.compile(
        r'(?:FROM|JOIN)\s+(?P<table>(?:(?:"[^"]+")|(?:[A-Za-z_][A-Za-z0-9_]*\.)?[A-Za-z_][A-Za-z0-9_]*))(?:\s+(?P<alias>(?:"[^"]+")|[A-Za-z_][A-Za-z0-9_]*))?',
        flags=re.IGNORECASE | re.DOTALL
    )
    
    # Extract all table names, deduplicate
    table_matches = table_pattern.finditer(code_no_comments)
    table_names = {match.group('table').strip() for match in table_matches}
    
    return sorted(table_names)

# Example usage
sample_procedure = """
CREATE OR REPLACE PROCEDURE get_emp_data IS
    CURSOR emp_cursor IS
        SELECT e.EMPNO, e.ENAME, d.DNAME
        FROM SCOTT.EMP e
        JOIN SCOTT.DEPT d ON e.DEPTNO = d.DEPTNO
        WHERE e.SAL > 5000;
    -- This is a comment: FROM dummy_table
    /* Another comment with FROM test_table */
BEGIN
    -- Procedure logic here
END;
"""

print(extract_oracle_table_names(sample_procedure))
# Output: ['SCOTT.DEPT', 'SCOTT.EMP']

4. Additional Enhancements (Optional)

  • Handle Subqueries: If you want to exclude tables from subqueries (since you asked for tables used to "get data"), you can modify the regex to avoid matching inside (SELECT ...). This gets trickier, but you can use negative lookaheads to skip subquery contexts.
  • Case Normalization: Convert all table names to uppercase (Oracle defaults to uppercase unless quoted) for consistency.
  • Alias Mapping: If you want to track which aliases map to which tables, return a dictionary instead of a set.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:14:46