以链表方式检索记录的算法

16 浏览
0 Comments

以链表方式检索记录的算法

我有一个MySQL表格,如下所示:

id name parent_id
19 category1 0
20 category2 19
21 category3 20
22 category4 21
... ... ...

现在,我想要只用一个MySQL查询来获取其所有子ID(例如,假设id=19),结果应该包含'20,21,22'的ID...

子ID的层次结构是未知的,可能会有所变化...

我知道如何使用for循环来做到这一点...但如何使用单个MySQL查询实现相同的功能?

0
0 Comments

问题的出现原因:在给定的数据库表中,有一个category表,其中每个记录都有一个parent_id字段,表示该记录的父记录的id。需要编写一个算法,以链表的方式检索category表中的记录。具体而言,需要找到每个记录的路径,即从根记录到该记录的所有父记录的连接字符串。

解决方法:通过使用递归存储过程和包装函数,可以实现从category表中检索记录的路径。首先,创建一个递归存储过程getpath,该存储过程接受一个cat_id参数和一个path输出参数。在存储过程中,首先定义了三个变量:catname(存储记录的名称)、temppath(存储父记录的路径)和tempparent(存储父记录的id)。然后,通过执行SELECT语句将记录的名称和父记录的id存储到相应的变量中。接下来,使用IF语句判断该记录是否有父记录。如果没有父记录,则将路径设置为记录的名称。如果有父记录,则调用getpath存储过程来获取父记录的路径,并使用CONCAT函数将父记录的路径与记录的名称连接起来,最终得到完整的路径。最后,使用包装函数getpath来调用递归存储过程,并返回路径作为结果。

通过执行SELECT语句,并调用getpath函数,可以检索category表中的记录及其路径。在输出结果中,每个记录都有一个id(记录的id)、name(记录的名称)和path(记录的路径)字段,显示了从根记录到该记录的完整路径。

此外,还可以使用过滤条件来筛选具有特定路径的记录。通过在SELECT语句中使用HAVING子句,并在其中使用path字段的LIKE运算符,可以实现对具有特定路径的记录进行筛选。输出结果将仅包含具有指定路径的记录。

注:在评论中提到,该解决方案对于具有多个子记录的情况可能无效。然而,其他人确认了该解决方案对于多个子记录也是有效的,并指出需要检查顶级父记录(categories)是否由parent_id字段的值为NULL或0来标识。因此,对于tempparent的检查条件应为:IF (tempparent IS NULL OR tempparent = 0)。

0
0 Comments

在MySQL中处理层次数据是一个常见的问题,因为关系数据库的表是扁平的,不支持层次结构。在这种情况下,我们需要一种算法来检索以链表方式存储的记录。以下是解决这个问题的算法和方法:

首先,我们需要一个类似下面的表结构:

+-------------+----------------------+--------+
| category_id | name                 | parent |
+-------------+----------------------+--------+
|           1 | ELECTRONICS          |   NULL |
|           2 | TELEVISIONS          |      1 |
|           3 | TUBE                 |      2 |
|           4 | LCD                  |      2 |
|           5 | PLASMA               |      2 |
|           6 | PORTABLE ELECTRONICS |      1 |
|           7 | MP3 PLAYERS          |      6 |
|           8 | FLASH                |      7 |
|           9 | CD PLAYERS           |      6 |
|          10 | 2 WAY RADIOS         |      6 |
+-------------+----------------------+--------+

然后,我们可以使用以下查询语句来检索记录:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS';

这将返回以下结果:

+-------------+----------------------+--------------+-------+

| lev1 | lev2 | lev3 | lev4 |

+-------------+----------------------+--------------+-------+

| ELECTRONICS | TELEVISIONS | TUBE | NULL |

| ELECTRONICS | TELEVISIONS | LCD | NULL |

| ELECTRONICS | TELEVISIONS | PLASMA | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |

| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL |

+-------------+----------------------+--------------+-------+

这个算法的原因是,在关系数据库中,表是扁平的,不支持层次结构。但是,这个查询语句使用了自连接的概念,将层次关系转换为链表形式,从而实现了检索功能。

虽然MySQL本身不支持递归查询,但是我们可以使用多个自连接来模拟递归查询。这个算法的解决方法就是使用多个自连接,并在每个连接中使用LEFT JOIN来检索层次关系的记录。

这个算法通过自连接和LEFT JOIN来模拟递归查询,将层次关系转换为链表形式,从而实现了检索功能。

0
0 Comments

从上面的内容中可以整理出以下问题的出现原因和解决方法:

问题:如何以链表的方式检索记录?

出现原因:MySQL的不同版本对于检索链表方式的支持不同,因此需要根据MySQL的版本来选择合适的解决方法。

解决方法:

1. MySQL 8+版本可以使用递归的with语法来检索记录。

示例代码:

with recursive cte (id, name, parent_id) as (
  select     id,
             name,
             parent_id
  from       products
  where      parent_id = 19
  union all
  select     p.id,
             p.name,
             p.parent_id
  from       products p
  inner join cte
          on p.parent_id = cte.id
)
select * from cte;

2. MySQL 5.x版本可以使用内联变量、路径ID或自连接来实现。

示例代码:

select  id,
        name,
        parent_id 
from    (select * from products
         order by parent_id, id) products_sorted,
        (select  := '19') initialisation
where   find_in_set(parent_id, )
and     length( := concat(, ',', id))

其中, := '19'的值应该设置为要选择所有后代的父级的id

此外,该解决方法对于某些情况可能效率较低,因为find_in_set操作不是在大数据集上查找数字的最理想方式。

如果MySQL版本支持,还可以考虑使用其他递归查询的语法,比如SQL:1999 ISO标准的WITH RECURSIVE语法或一些数据库特定的语法(如Oracle的CONNECT BY子句)。

另外,还可以通过给每个记录分配包含层级信息的新生成的键来简化操作。

以上是解决问题的几种方法,具体选择哪种取决于MySQL的版本和需求。

0