ExtJS 7树形结构构建:MySQL双表合并查询适配不同TreeList需求
看起来你是在ExtJS 7里搭建树形组件时卡壳了——要把两个结构相同的MySQL表当成一个数据源,还要给两个TreeList分别提供“不含真实叶子节点”和“包含真实叶子节点”的数据集,之前试了JOIN系列操作没效果对吧?我之前做类似需求时也踩过这个坑,给你梳理几个可行的方案:
核心误区先理清:为什么JOIN没用?
你之前尝试的JOIN、LEFT JOIN是用来关联两个表的关联数据(比如A表的id对应B表的parentId),但你的需求是把两个表的行数据直接合并,就像把两个相同结构的Excel表合并成一个工作表,这时候应该用UNION ALL(比UNION高效,因为不会自动去重),这是解决问题的核心。
方案1:直接用UNION ALL合并双表+按需过滤叶子节点
假设你的两个表分别是lv_tree和employee_tree(你没给表名,我先这么命名),且表里有id、parentId、is_leaf(标记是否为真实叶子节点)字段,那可以这么写查询:
场景1:TreeList不需要真实叶子节点
SELECT * FROM ( SELECT * FROM `lv_tree` UNION ALL SELECT * FROM `employee_tree` ) AS combined_tree WHERE parentId = ? AND is_leaf = 0
这里通过is_leaf = 0过滤掉所有真实叶子节点,只保留非叶子节点供TreeList展示。
场景2:员工用TreeList需要包含真实叶子节点
SELECT * FROM ( SELECT * FROM `lv_tree` UNION ALL SELECT * FROM `employee_tree` ) AS combined_tree WHERE parentId = ?
这个场景不需要额外过滤,直接返回合并后所有符合parentId的节点。
方案2:提前创建视图封装合并逻辑(代码更简洁)
如果你的业务里经常需要用到这个合并后的数据集,不如直接创建一个MySQL视图,后续查询直接调用视图就行,不用每次都写UNION ALL:
1. 创建合并视图
CREATE VIEW `combined_tree_view` AS SELECT * FROM `lv_tree` UNION ALL SELECT * FROM `employee_tree`;
2. 场景1调用(无真实叶子节点)
SELECT * FROM `combined_tree_view` WHERE parentId = ? AND is_leaf = 0
3. 场景2调用(包含真实叶子节点)
SELECT * FROM `combined_tree_view` WHERE parentId = ?
特殊情况:如果表没有is_leaf标记字段怎么办?
如果你的表没提前标记叶子节点,那可以通过子查询动态判断当前节点是否有子节点,从而生成is_leaf字段:
SELECT ct.*, -- 判断当前节点是否有子节点,没有就是叶子节点 NOT EXISTS ( SELECT 1 FROM ( SELECT id FROM `lv_tree` UNION ALL SELECT id FROM `employee_tree` ) AS child_nodes WHERE child_nodes.parentId = ct.id ) AS is_leaf FROM ( SELECT * FROM `lv_tree` UNION ALL SELECT * FROM `employee_tree` ) AS ct WHERE ct.parentId = ?
然后你就可以像方案1一样,通过is_leaf = 0来过滤叶子节点了。
适配你的PHP代码示例
把上面的SQL套进你原来的PHP逻辑里就行:
场景1:无真实叶子节点的TreeList查询
$sql = 'SELECT * FROM `combined_tree_view` WHERE parentId = ? AND is_leaf = 0'; $result = $db->connect()->prepare($sql); $result->bindParam(1, $_REQUEST['node']); $result->execute();
场景2:员工用TreeList查询
$sql = 'SELECT * FROM `combined_tree_view` WHERE parentId = ?'; $result = $db->connect()->prepare($sql); $result->bindParam(1, $_REQUEST['node']); $result->execute();
小提示:避免用*,明确指定字段更安全
虽然你说两个表结构相同,但为了避免后续表结构变更导致的问题,建议在UNION ALL里明确写出需要的字段,比如:
SELECT id, parentId, node_name, is_leaf FROM `lv_tree` UNION ALL SELECT id, parentId, node_name, is_leaf FROM `employee_tree`
内容来源于stack exchange

