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

Python提取含笛卡尔连接SQL的表与列名(Python2.7报错求助)

Fixing "Bool object not callable" Error & Extracting Tables/Columns from Cartesian Join SQL (Python 2.7)

Hey there! Let's break this down into two clear parts: fixing that frustrating error, then building the SQL table/column extractor you need.

First: Squashing the "Bool object not callable" Error

That error almost always pops up when you accidentally treat a boolean variable like a function. For example, if you had code like this:

is_parsed = True
if is_parsed():  # Oops! is_parsed is a boolean, not a function
    print("Parsing done")

Python 2.7 throws this error because you're trying to "call" a boolean value like it's a method. The fix is simple—just remove the parentheses after the boolean variable:

is_parsed = True
if is_parsed:
    print("Parsing done")

Double-check your code for any places where you added extra parentheses to a boolean variable or expression—that's almost certainly the root cause here.

Second: Extracting Table Names & Columns from Cartesian Join SQL

Parsing SQL manually with regex is a huge headache (especially with subqueries like your example), so we'll use the sqlparse library—it handles SQL syntax properly without the mess of regex. Note that for Python 2.7, you'll need an older version of sqlparse (0.4.4 is the last release that supports Python 2.x).

Step 1: Install sqlparse

Run this in your terminal:

pip install sqlparse==0.4.4

Step 2: The Extractor Code

Here's a script that parses your SQL, pulls out table names (including subquery aliases) and column names reliably:

import sqlparse
from sqlparse.sql import IdentifierList, Identifier
from sqlparse.tokens import Token

def extract_tables_and_columns(sql):
    parsed = sqlparse.parse(sql)[0]
    
    tables = set()
    columns = set()
    
    # Extract columns from SELECT clause
    select_clause = None
    for token in parsed.tokens:
        if token.ttype is None and token.value.upper() == 'SELECT':
            idx = parsed.tokens.index(token)
            select_clause = parsed.tokens[idx + 1]
            break
    
    if select_clause:
        for item in select_clause.get_identifiers():
            # Handle aliased columns (e.g., SUM(orders.amount) AS total_amt)
            if isinstance(item, Identifier):
                col_name = item.get_real_name()
                if '.' in col_name:
                    columns.add(col_name)
                else:
                    columns.add(col_name)
            else:
                # Extract columns wrapped in functions
                func_str = str(item)
                if '(' in func_str and ')' in func_str:
                    inner_col = func_str.split('(')[1].split(')')[0].strip()
                    if '.' in inner_col:
                        columns.add(inner_col)
    
    # Extract tables from FROM clause (including Cartesian joins and subqueries)
    from_clause = None
    for token in parsed.tokens:
        if token.ttype is None and token.value.upper() == 'FROM':
            idx = parsed.tokens.index(token)
            from_clause = parsed.tokens[idx + 1]
            break
    
    if from_clause:
        def extract_table_identifiers(token):
            if isinstance(token, IdentifierList):
                for item in token.get_identifiers():
                    extract_table_identifiers(item)
            elif isinstance(token, Identifier):
                # Handle subqueries with aliases
                if token.has_alias():
                    tables.add(token.get_alias())
                    # Recursively parse tables inside the subquery
                    subquery = token.token_first()
                    if subquery and subquery.value == '(':
                        sub_sql = str(token.token_next(1)).strip(')')
                        sub_tables, _ = extract_tables_and_columns(sub_sql)
                        tables.update(sub_tables)
                else:
                    tables.add(token.get_real_name())
            elif token.ttype is Token.Punctuation and token.value == ',':
                pass
            else:
                # Dig into nested tokens (like subquery parentheses)
                if hasattr(token, 'tokens'):
                    for sub_token in token.tokens:
                        extract_table_identifiers(sub_token)
        
        extract_table_identifiers(from_clause)
    
    return sorted(tables), sorted(columns)

# Test with your sample SQL
sample_sql = """SELECT suppliers.supplier_name, subquery1.total_amt FROM suppliers , (SELECT supplier_id, SUM(orders.amount) AS total_amt FROM orders GROUP BY supplier_id) subquery1 WHERE subquery1.supplier_id = suppliers.supplier_id;"""
tables, columns = extract_tables_and_columns(sample_sql)

print("Extracted Tables:")
for table in tables:
    print(f"- {table}")

print("\nExtracted Columns:")
for col in columns:
    print(f"- {col}")

Step 3: What This Does

  • Avoids the boolean error: The code doesn't make the mistake of calling boolean values, so you won't hit that issue here.
  • Extracts tables: Pulls out regular tables (suppliers, orders) and subquery aliases (subquery1), and even recursively parses subqueries to grab tables inside them.
  • Extracts columns: Captures columns with table prefixes (suppliers.supplier_name, orders.amount) and aliased columns from subqueries (subquery1.total_amt).

Output for Your Sample SQL

When you run the script, you'll get:

Extracted Tables:
- orders
- subquery1
- suppliers

Extracted Columns:
- orders.amount
- subquery1.supplier_id
- subquery1.total_amt
- suppliers.supplier_id
- suppliers.supplier_name

Quick Notes

  • This code handles your specific case smoothly, but for ultra-complex SQL (like deeply nested subqueries), you might need to tweak the parsing logic slightly.
  • Python 2.7 is end-of-life, so if you can, consider upgrading to Python 3.x for better support—but this code works perfectly for your 2.7 requirement.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:01:32