【问题标题】:Simplify recursive mysql query简化递归mysql查询
【发布时间】:2019-07-22 10:13:41
【问题描述】:

使用给定的 MySQL 表

CREATE TABLE taxons (
    id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
    parent_id int,
    name varchar(255)
);

该表有以下条目

INSERT INTO taxons (parent_id, name) VALUES (NULL, "Baby & Kleinkind"); 
INSERT INTO taxons (parent_id, name) VALUES (1, "Babysicherheit"); 
INSERT INTO taxons (parent_id, name) VALUES (2, "Babysicherungen & Schutzvorrichtungen"); 

关卡数量无穷无尽。

我想通过向下遍历树来选择一个只有一个查询的实体(一个分类单元)。

目前我的查询是手工制作的

SELECT * 
FROM taxons
WHERE name = "Babysicherungen & Schutzvorrichtungen" 
AND parent_id = (
  SELECT id 
  FROM taxons 
  WHERE name  = "Babysicherheit"
  AND parent_id = (
    SELECT id 
    FROM taxons 
    WHERE name = "Baby & Kleinkind"
  )
);

这个查询有没有更好的解决方案?

请参阅 db fiddle 以获得更好的理解:https://www.db-fiddle.com/f/mvMCGdNgjCa9PeNKbbzmRL/0

MySQL v5.7

【问题讨论】:

标签: mysql recursion traversal


【解决方案1】:

如果我正确阅读了您的查询,您希望查询顶级记录,但只查询所有子行都存在的那些记录。例如,如果某个 ID 不存在“Baby & Kleinkind”,那么我们不需要该 ID。

如果是这样,您可以使用动态 SQL 构建一个自动检查每个父子关系的查询。如果您有很多分类单元,这可以节省您的时间。

这个想法是构建一个看起来像这样的查询(假设有五个分类单元):

SELECT t1.* 
FROM taxons t1
INNER JOIN taxons t2
  ON t1.id = t2.parent_id 
INNER JOIN taxons t3
  ON t2.id = t3.parent_id
INNER JOIN taxons t4
  ON t3.id = t4.parent_id
INNER JOIN taxons t5
  ON t4.id = t5.parent_id
WHERE NAME = "Babysicherungen & Schutzvorrichtungen" 

要构建它,您可以使用循环:

DECLARE totalLevels INT;
DECLARE num INT;
DECLARE queryString VARCHAR(255);

SET @totalLevels = 5
SET @num = 2;
SET @str = 'SELECT t1.* 
FROM taxons t1';

build_query: LOOP
  IF @num > @totalLevels THEN
    LEAVE build_query;
  END IF;
  SET @queryString = CONCAT(@queryString,
    ' INNER JOIN taxons t', num, ' ON t', num-1, '.id = t', num, '.parent_id'
  );
  SET @num = @num + 1;
  ITERATE build_query;
END LOOP;

SET @queryString = CONCAT(@queryString, ' WHERE NAME = "Babysicherungen & Schutzvorrichtungen"')

您可以使用 totalLevels 设置要遍历的分类单元的总数。

我没有专门测试该循环中的代码,但我过去做过类似的查询,它应该可以工作,或者只需要进行微小的更改即可工作。

编辑:我忘了添加,一旦你创建了查询字符串,你需要执行它。为此,请参见此处: Is it possible to execute a string in MySQL?

【讨论】:

    【解决方案2】:

    更简洁的表达方式是使用连接:

    select t1.* from taxons t1
    join taxons t2 on t1.name = "Babysicherungen & Schutzvorrichtungen" and t1.parent_id = t2.id and t2.name = "Babysicherheit"
    join taxons t3 on t2.parent_id = t3.id and t3.name="Baby & Kleinkind"
    ;
    

    鉴于您已定义(或缺少)键,它也会更有效。请参阅您的 SQL 和上面的两个 EXPLAIN 分析:

    架构 (MySQL v5.7)

    CREATE TABLE taxons (
        id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
        parent_id int,
        name varchar(255)
    );
    
    INSERT INTO taxons (parent_id, name) VALUES (NULL, "Baby & Kleinkind"); 
    INSERT INTO taxons (parent_id, name) VALUES (1, "Babysicherheit"); 
    INSERT INTO taxons (parent_id, name) VALUES (2, "Babysicherungen & Schutzvorrichtungen"); 
    

    查询 #1

    EXPLAIN SELECT * 
    FROM taxons
    WHERE name = "Babysicherungen & Schutzvorrichtungen" 
    AND parent_id = (
      SELECT id 
      FROM taxons 
      WHERE name  = "Babysicherheit"
      AND parent_id = (
        SELECT id 
        FROM taxons 
        WHERE name = "Baby & Kleinkind"
      )
    );
    

    |编号 |选择类型 |表|隔断 |类型 |可能的键 |关键 | key_len |参考 |行 |过滤 |额外 | | --- | ------------ | ------ | ---------- | ---- | ------------- | --- | -------- | --- |

    ---- | -------- | ----------- |
    | 1   | PRIMARY     | taxons |            | ALL  |               |     |         |     | 3    | 33.33    | Using where |
    | 2   | SUBQUERY    | taxons |            | ALL  |               |     |         |     | 3    | 33.33    | Using where |
    | 3   | SUBQUERY    | taxons |            | ALL  |               |     |         |     | 3    | 33.33    | Using where |
    
    ---
    

    View on DB Fiddle

    架构 (MySQL v5.7)

    CREATE TABLE taxons (
        id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
        parent_id int,
        name varchar(255)
    );
    
    INSERT INTO taxons (parent_id, name) VALUES (NULL, "Baby & Kleinkind"); 
    INSERT INTO taxons (parent_id, name) VALUES (1, "Babysicherheit"); 
    INSERT INTO taxons (parent_id, name) VALUES (2, "Babysicherungen & Schutzvorrichtungen"); 
    

    查询 #1

    EXPLAIN select t1.* from taxons t1
    join taxons t2 on t1.name = "Babysicherungen & Schutzvorrichtungen" and t1.parent_id = t2.id and t2.name = "Babysicherheit"
    join taxons t3 on t2.parent_id = t3.id and t3.name="Baby & Kleinkind"
    ;
    
    | id  | select_type | table | partitions | type   | possible_keys | key     | key_len | ref               | rows | filtered | Extra       |
    | --- | ----------- | ----- | ---------- | ------ | ------------- | ------- | ------- | ----------------- | ---- | -------- | ----------- |
    | 1   | SIMPLE      | t1    |            | ALL    |               |         |         |                   | 3    | 33.33    | Using where |
    | 1   | SIMPLE      | t2    |            | eq_ref | PRIMARY       | PRIMARY | 4       | test.t1.parent_id | 1    | 33.33    | Using where |
    | 1   | SIMPLE      | t3    |            | eq_ref | PRIMARY       | PRIMARY | 4       | test.t2.parent_id | 1    | 33.33    | Using where |
    

    View on DB Fiddle

    【讨论】:

    • 太棒了!没想过加入!
    猜你喜欢
    • 2023-03-12
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 2014-03-19
    • 2019-03-09
    • 1970-01-01
    • 2019-05-14
    • 2012-02-16
    相关资源
    最近更新 更多