重构 MySQL 查询

Refactoring MySQL query

我们提出了这个查询:

SELECT tn1.* FROM tree_node tn1
WHERE tn1.type != "folder" AND tn1.parent IN (
    SELECT tn.id FROM tree_node tn
    LEFT JOIN tree_node_access tna ON tna.tree_node_id = tn.id
    WHERE (tn.project_id = 50 AND tna.access = 0 AND (tna.user_id = 8 OR tna.user_group_id IN (26)))
) OR tn1.id IN (
    SELECT tn.id FROM tree_node tn
    LEFT JOIN tree_node_access tna ON tna.tree_node_id = tn.id
    WHERE (tn.project_id = 50 AND tna.access = 0 AND (tna.user_id = 8 OR tna.user_group_id IN (26)))
)

但必须有可能不必重复子查询两次,因为该查询完全相同。

有没有办法重构这个查询?

您可以将 or 替换为 UNION,将子查询替换为 JOIN:

SELECT tn1.*
FROM tree_node tn1
INNER JOIN tree_node tn
ON tn1.parent=tn.id
LEFT JOIN tree_node_access tna
ON tna.tree_node_id = tn.id
WHERE tn1.type != 'folder'
AND (tn.project_id = 50 AND tna.access = 0 AND (tna.user_id = 8 OR tna.user_group_id IN (26)))
UNION
SELECT tn1.*
FROM tree_node tn1
INNER JOIN tree_node tn
ON tn.id=tn1.id
LEFT JOIN tree_node_access tna
ON tna.tree_node_id = tn.id
WHERE (tn.project_id = 50 AND tna.access = 0 AND (tna.user_id = 8 OR tna.user_group_id IN (26)))

您没有说明您使用的 MySQL 版本。在 MySQL 8.x 中,您可以为其使用 CTE(通用 Table 表达式)。

例如:

with
a as (
  SELECT tn.id FROM tree_node tn
  LEFT JOIN tree_node_access tna ON tna.tree_node_id = tn.id
  WHERE (tn.project_id = 50 AND tna.access = 0 
    AND (tna.user_id = 8 OR tna.user_group_id IN (26)))
)
SELECT tn1.* FROM tree_node tn1
WHERE tn1.type != "folder" AND tn1.parent IN (select id from a)
   OR tn1.id IN (select id from a)