如何用Python实现SQL树形数据库的节点子孙薪资求和?
解决方案
首先需要明确:你的示例存在规则歧义——0x123的结果是仅子孙节点薪资总和(不含自身),但0x456和0x789的结果是自身+子孙节点薪资总和。下面针对两种常见规则给出实现,你可以根据实际需求选择。
前提:将数据库数据转为可快速查询的结构
先从SQL数据库读取所有记录,转换成字典映射,方便后续快速查询任意节点的子节点和薪资:
import sqlite3 # 若用MySQL等其他数据库,替换为对应驱动(如pymysql) def load_node_data(db_path): conn = sqlite3.connect(db_path) cursor = conn.cursor() # 假设表名为node_salary,字段名对应Mother, Child1, Child2, Salary cursor.execute("SELECT Mother, Child1, Child2, Salary FROM node_salary") node_map = {} for mother, child1, child2, salary in cursor.fetchall(): # 过滤空的子节点 valid_children = [child for child in (child1, child2) if child is not None] node_map[mother] = {"children": valid_children, "salary": salary} conn.close() return node_map
实现1:仅计算子孙节点薪资总和(匹配0x123示例)
该实现只累加目标节点的所有后代(直接/间接子节点)的薪资,不含目标节点自身:
递归版
def get_descendant_salary_sum(node_id, node_map): total = 0 if node_id not in node_map: return total # 遍历当前节点的所有子节点 for child in node_map[node_id]["children"]: # 累加子节点薪资 total += node_map[child]["salary"] # 递归累加子节点的后代薪资 total += get_descendant_salary_sum(child, node_map) return total
迭代版(避免递归栈溢出,适合大量数据)
def get_descendant_salary_sum_iter(node_id, node_map): total = 0 if node_id not in node_map: return total # 用队列存储待遍历的后代节点 queue = node_map[node_id]["children"].copy() while queue: current_node = queue.pop(0) if current_node not in node_map: continue total += node_map[current_node]["salary"] # 将当前节点的子节点加入队列 queue.extend(node_map[current_node]["children"]) return total
测试结果:
node_map = load_node_data("your_db.db") print(get_descendant_salary_sum("0x123", node_map)) # 230(符合示例) print(get_descendant_salary_sum("0x456", node_map)) # 120(与示例180不符) print(get_descendant_salary_sum("0x789", node_map)) # 0(与示例50不符)
实现2:计算自身+所有子孙节点薪资总和(匹配0x456/0x789示例)
该实现累加目标节点自身及所有后代的薪资:
递归版
def get_self_descendant_sum(node_id, node_map): if node_id not in node_map: return 0 total = node_map[node_id]["salary"] # 遍历子节点并递归累加 for child in node_map[node_id]["children"]: total += get_self_descendant_sum(child, node_map) return total
迭代版
def get_self_descendant_sum_iter(node_id, node_map): total = 0 if node_id not in node_map: return total queue = [node_id] while queue: current_node = queue.pop(0) total += node_map[current_node]["salary"] queue.extend(node_map[current_node]["children"]) return total
测试结果:
print(get_self_descendant_sum("0x123", node_map)) # 310(与示例230不符) print(get_self_descendant_sum("0x456", node_map)) # 180(符合示例) print(get_self_descendant_sum("0x789", node_map)) # 50(符合示例)
匹配所有示例的折中实现
如果必须严格匹配你给出的所有示例,推测规则为:根节点仅算子孙,非根节点算自身+子孙。但这个规则逻辑不合理,仅作参考:
def get_sum_matching_all_examples(node_id, node_map, root_id="0x123"): if node_id == root_id: return get_descendant_salary_sum(node_id, node_map) else: return get_self_descendant_sum(node_id, node_map)
测试结果:
print(get_sum_matching_all_examples("0x123", node_map)) # 230 print(get_sum_matching_all_examples("0x456", node_map)) # 180 print(get_sum_matching_all_examples("0x789", node_map)) # 50
内容的提问来源于stack exchange,提问作者Cena Masoumi
相关产品推荐
相关产品推荐

