如何为Python __select__方法的process_sql_query添加括号支持?
扩展process_sql_query函数支持带括号的WHERE子句条件分组
要支持带括号的条件分组,核心是处理逻辑运算的优先级与嵌套分组,最直观的实现方式是用栈结构维护嵌套的条件上下文,同时兼顾AND/OR的默认优先级(AND高于OR)。以下是具体实现思路和代码:
实现步骤
1. 预处理:将WHERE子句拆分为标记流(Tokens)
先把原始WHERE字符串拆分为可解析的标记,包括括号、逻辑运算符(AND/OR)、单个条件片段。拆分时要保留括号完整性,同时忽略多余空格,还要兼容带引号的条件(比如status = 'active')。
2. 栈结构处理嵌套分组
用栈存储当前的条件上下文,每个上下文包含两个元素:
- 当前组的条件列表
- 当前组的逻辑运算符(用于合并条件)
遇到左括号时压入当前上下文,开启新的子组;遇到右括号时弹出栈顶,将子组的结果合并到上层上下文。
3. 处理AND/OR优先级
默认AND优先级高于OR,因此遇到OR时,需要先将当前已有的AND组合条件合并为一个整体,再加入OR的逻辑分支。
完整代码实现
def evaluate_condition(row, condition): # 单个条件的判断逻辑示例(生产环境建议用ast解析替代eval) return eval(condition, {}, row) def tokenize_where_clause(where_clause): # 拆分WHERE子句为标记流,兼容带引号的条件 tokens = [] current_token = [] in_quotes = False for char in where_clause: if char in ('"', "'"): in_quotes = not in_quotes current_token.append(char) elif not in_quotes and char in '()': if current_token: tokens.append(''.join(current_token).strip()) current_token = [] tokens.append(char) elif not in_quotes and char.isspace(): if current_token: tokens.append(''.join(current_token).strip()) current_token = [] else: current_token.append(char) if current_token: tokens.append(''.join(current_token).strip()) return [t for t in tokens if t] def process_sql_query(where_clause, data): if not where_clause: return data tokens = tokenize_where_clause(where_clause) # 栈元素:(条件列表, 当前逻辑运算符),初始上下文用OR作为默认(不影响单个条件) stack = [([], 'OR')] current_conditions, current_op = stack[-1] i = 0 while i < len(tokens): token = tokens[i] if token == '(': # 压入当前上下文,开启新子组 stack.append(([], 'OR')) current_conditions, current_op = stack[-1] i += 1 elif token == ')': # 弹出子组,合并到上层上下文 stack.pop() if not stack: raise SyntaxError("WHERE子句括号不匹配") parent_conditions, parent_op = stack[-1] # 将子组条件封装为可调用的判断函数 def sub_group_check(row, conds=current_conditions, op=current_op): if op == 'AND': return all(evaluate_condition(row, cond) for cond in conds) else: return any(evaluate_condition(row, cond) for cond in conds) parent_conditions.append(sub_group_check) current_conditions, current_op = parent_conditions, parent_op i += 1 elif token in ('AND', 'OR'): # 更新当前上下文的逻辑运算符 current_op = token stack[-1] = (current_conditions, current_op) i += 1 else: # 普通条件加入当前上下文 current_conditions.append(token) i += 1 if len(stack) != 1: raise SyntaxError("WHERE子句括号不匹配") # 最终条件判断逻辑 final_conditions, final_op = stack[0] def final_check(row): if final_op == 'AND': for cond in final_conditions: if callable(cond): if not cond(row): return False else: if not evaluate_condition(row, cond): return False return True else: for cond in final_conditions: if callable(cond): if cond(row): return True else: if evaluate_condition(row, cond): return True return False # 过滤数据 return [row for row in data if final_check(row)]
代码关键点说明
- tokenize_where_clause:处理带引号的条件,避免把引号内的空格或括号误拆分,确保标记流的正确性。
- 栈上下文管理:每个括号组对应一个栈元素,嵌套分组时通过压栈/弹栈切换上下文,保证括号内的条件被独立处理。
- 嵌套条件合并:将括号内的子条件转换为可调用的判断函数,上层上下文直接调用该函数即可完成分组判断。
- 优先级处理:同一上下文内的AND条件会被先合并为连续的
all()判断,OR则作为分支用any()判断,符合AND优先级高于OR的规则。
使用示例
# 测试数据 sample_data = [ {'age': 35, 'status': 'active', 'salary': 60000, 'department': 'tech'}, {'age': 28, 'status': 'inactive', 'salary': 45000, 'department': 'admin'}, {'age': 40, 'status': 'active', 'salary': 55000, 'department': 'sales'}, ] # 带括号的WHERE子句 where_clause = "(age > 30 AND status = 'active') OR (salary > 50000 AND department = 'tech')" # 处理查询 result = process_sql_query(where_clause, sample_data) print(result) # 输出:[{'age': 35, 'status': 'active', 'salary': 60000, 'department': 'tech'}, {'age': 40, 'status': 'active', 'salary': 55000, 'department': 'sales'}]
内容的提问来源于stack exchange,提问作者Celer
相关产品推荐
相关产品推荐

