php 怎么进行无限级查询
-
在PHP中进行无限级查询可以使用递归方法。下面是一个简单的示例代码:
“`php
connect_error) {
die(“连接失败: ” . $conn->connect_error);
}// 定义一个递归函数来进行无限级查询
function getCategory($parent_id, $conn, $level = 0) {
// 构建查询语句
$sql = “SELECT * FROM categories WHERE parent_id = $parent_id”;// 执行查询
$result = $conn->query($sql);// 检查查询结果是否为空
if ($result->num_rows > 0) {
// 输出查询结果
while($row = $result->fetch_assoc()) {
echo str_repeat(‘-‘, $level) . $row[‘name’] . “
“;
// 递归调用自身查询子分类
getCategory($row[‘id’], $conn, $level + 1);
}
}
}// 调用递归函数查询顶级分类
getCategory(0, $conn);// 关闭数据库连接
$conn->close();
?>
“`以上示例代码实现了一个基本的无限级分类查询。首先定义了数据库连接信息,然后与数据库建立连接。接着定义了一个递归函数 getCategory 来进行查询。该函数首先构建查询语句,然后执行查询并将查询结果输出。在函数内部,通过递归调用自身来查询子分类,同时通过增加一个 level 参数来控制缩进显示层级关系。最后,调用该递归函数并传入顶级分类的 parent_id(通常为0)来开始查询。
请根据自己的数据库表结构和需求进行相应的修改。
2年前 -
在PHP中,要进行无限级查询,可以使用递归方法来实现。以下是实现无限级查询的步骤:
步骤1:准备数据
首先,需要准备一张数据表来存储无限级分类的数据。表中至少需要包含两个字段,一个是主键字段,用来唯一标识每个分类;另一个是父级分类的ID,用来标识当前分类的父级分类。可以在数据库中创建一个名为”categories”的表,如下所示:CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
parent_id INT,
name VARCHAR(255)
);步骤2:插入数据
在数据表中插入一些分类数据,用于测试。可以使用如下的SQL语句:INSERT INTO categories (parent_id, name)
VALUES (NULL, ‘分类1’),
(1, ‘分类2’),
(1, ‘分类3’),
(2, ‘分类4’),
(2, ‘分类5’),
(3, ‘分类6’);步骤3:创建递归函数
在PHP代码中,创建一个递归函数来查询无限级分类的数据。函数可以接受一个参数,表示当前分类的父级分类ID。在函数内部,先查询当前分类的子级分类,然后再递归调用自身,查询子级分类的子级分类,以此类推。函数的代码如下所示:function getCategories($parentId = NULL) {
$sql = “SELECT * FROM categories WHERE parent_id = :parentId”;
$stmt = $pdo->prepare($sql);
$stmt->bindValue(‘:parentId’, $parentId, PDO::PARAM_INT);
$stmt->execute();
$categories = $stmt->fetchAll();$result = [];
foreach ($categories as $category) {
$children = getCategories($category[‘id’]);
$category[‘children’] = $children;
$result[] = $category;
}return $result;
}步骤4:测试函数
调用上述创建的函数,测试无限级查询的功能。可以使用如下的代码:$categories = getCategories();
var_dump($categories);运行代码后,可以看到输出的结果是一个多维数组,包含了所有的分类信息及其子级分类信息。可以根据需要对查询结果进行处理,展示在网页上或者其他地方。
上述是在PHP中进行无限级查询的基本步骤。根据实际需求,可能需要对查询结果进行排序、分页等操作。
2年前 -
PHP无限级查询可以使用数据库中的递归关系来实现。在数据库设计中,通常使用两种方法来实现无限级查询:嵌套集合模型和闭包表模型。本文将详细讲解这两种方法的操作流程和使用方式。
## 一、嵌套集合模型
### 1. 数据库表设计
在使用嵌套集合模型实现无限级查询时,首先需要设计数据库表。常见的表设计如下:
“`sql
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
“`其中,`id`字段是分类的唯一标识,`name`字段是分类的名称,`lft`字段和`rgt`字段用于表示分类在树状结构中的左边界和右边界。具体的表数据可以根据实际需求进行插入。
### 2. 添加分类
使用PHP操作数据库,可以使用`PDO`扩展或者其他数据库操作类库来实现。具体的操作流程如下:
“`php
beginTransaction();// 查询父级分类信息
if ($parent_id) {
$stmt = $dbh->prepare(‘SELECT * FROM categories WHERE id = :parent_id’);
$stmt->bindParam(‘:parent_id’, $parent_id);
$stmt->execute();
$parent_category = $stmt->fetch(PDO::FETCH_ASSOC);// 更新右边界
$stmt = $dbh->prepare(‘UPDATE categories SET rgt = rgt + 2 WHERE rgt >= :parent_rgt’);
$stmt->bindParam(‘:parent_rgt’, $parent_category[‘rgt’]);
$stmt->execute();// 更新左边界
$stmt = $dbh->prepare(‘UPDATE categories SET lft = lft + 2 WHERE lft > :parent_rgt’);
$stmt->bindParam(‘:parent_rgt’, $parent_category[‘rgt’]);
$stmt->execute();$left = $parent_category[‘rgt’];
$right = $parent_category[‘rgt’] + 1;
} else {
// 查询最大右边界
$stmt = $dbh->prepare(‘SELECT MAX(rgt) as max_rgt FROM categories’);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$left = $result[‘max_rgt’] + 1;
$right = $result[‘max_rgt’] + 2;
}// 添加分类
$stmt = $dbh->prepare(‘INSERT INTO categories (name, lft, rgt) VALUES (:name, :left, :right)’);
$stmt->bindParam(‘:name’, $name);
$stmt->bindParam(‘:left’, $left);
$stmt->bindParam(‘:right’, $right);
$stmt->execute();// 提交事务
$dbh->commit();
}
“`上述代码中的`addCategory`函数用于添加分类,其中`parent_id`参数表示父级分类的ID,默认为`null`,表示根分类。函数首先会查询父级分类的信息,然后根据父级分类的右边界来更新其他分类的左右边界,在新增分类时同时更新左边界和右边界。具体操作都是使用MySQL的更新语句完成的。最后通过事务的方式来保证数据的一致性。
### 3. 查询分类
查询分类的过程就是根据嵌套集合模型的左右边界进行查询。可以使用递归的方式来实现查询所有子分类的功能。具体的操作流程如下:
“`php
prepare(‘SELECT * FROM categories WHERE lft > :left AND rgt < :right'); $stmt->bindParam(‘:left’, $left);
$stmt->bindParam(‘:right’, $right);
$stmt->execute();
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);foreach ($categories as &$category) {
$category[‘name’] = str_repeat(‘-‘, $depth) . $category[‘name’];
$category[‘children’] = getCategories($category[‘id’], $depth + 1);
}return $categories;
}
“`上述代码中的`getCategories`函数接收两个参数,`parent_id`表示要查询的父级分类的ID,默认为`null`,表示根分类;`depth`表示当前分类的层级深度,默认为0。函数首先根据父级分类的左右边界查询子分类,然后使用递归的方式查询每个子分类的子分类,并将结果保存在每个分类的`children`字段中。同时根据分类的深度调整分类的名称,在名称前加上相应数量的横线。
### 4. 更新分类
更新分类的操作流程和添加分类类似,只是需要调整左右边界的值。具体的操作流程如下:
“`php
prepare(‘SELECT * FROM categories WHERE id = :id’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();
$category = $stmt->fetch(PDO::FETCH_ASSOC);// 更新分类名称
$stmt = $dbh->prepare(‘UPDATE categories SET name = :name WHERE id = :id’);
$stmt->bindParam(‘:name’, $name);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();// 计算需要增加或减少的值
$diff = strlen($name) – strlen($category[‘name’]);// 更新子分类的左右边界
$stmt = $dbh->prepare(‘UPDATE categories SET lft = lft + :diff, rgt = rgt + :diff WHERE lft > :left AND rgt < :right'); $stmt->bindParam(‘:diff’, $diff);
$stmt->bindParam(‘:left’, $category[‘lft’]);
$stmt->bindParam(‘:right’, $category[‘rgt’]);
$stmt->execute();
}
“`上述代码中的`updateCategory`函数用于更新分类的名称。函数首先查询分类的原始名称,然后更新分类的名称,最后根据分类名称的增加或减少来调整子分类的左右边界。
### 5. 删除分类
删除分类的操作流程也与添加分类类似,需要调整左右边界的值。具体的操作流程如下:
“`php
prepare(‘SELECT * FROM categories WHERE id = :id’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();
$category = $stmt->fetch(PDO::FETCH_ASSOC);// 开启事务
$dbh->beginTransaction();// 删除分类及其所有子分类
$stmt = $dbh->prepare(‘DELETE FROM categories WHERE lft >= :left AND rgt <= :right'); $stmt->bindParam(‘:left’, $category[‘lft’]);
$stmt->bindParam(‘:right’, $category[‘rgt’]);
$stmt->execute();// 更新左右边界
$diff = $category[‘rgt’] – $category[‘lft’] + 1;
$stmt = $dbh->prepare(‘UPDATE categories SET lft = lft – :diff WHERE lft > :right’);
$stmt->bindParam(‘:diff’, $diff);
$stmt->bindParam(‘:right’, $category[‘rgt’]);
$stmt->execute();$stmt = $dbh->prepare(‘UPDATE categories SET rgt = rgt – :diff WHERE rgt > :right’);
$stmt->bindParam(‘:diff’, $diff);
$stmt->bindParam(‘:right’, $category[‘rgt’]);
$stmt->execute();// 提交事务
$dbh->commit();
}
“`上述代码中的`deleteCategory`函数用于删除分类。函数首先查询分类的信息,然后通过事务的方式删除分类及其所有子分类,在删除分类后需要调整左右边界的值,具体操作与添加分类和更新分类类似。
## 二、闭包表模型
### 1. 数据库表设计
闭包表模型是另一种实现无限级查询的方法。在使用闭包表模型时,需要添加一张额外的表来保存分类之间的关系。常见的表设计如下:
“`sql
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);CREATE TABLE categories_closure (
ancestor_id INT NOT NULL,
descendant_id INT NOT NULL,
depth INT NOT NULL,
PRIMARY KEY (ancestor_id, descendant_id)
);
“`其中,`categories`表用于保存分类的基本信息,`categories_closure`表用于保存分类之间的关系。具体的表数据可以根据实际需求进行插入。
### 2. 添加分类
使用PHP操作数据库,可以使用`PDO`扩展或者其他数据库操作类库来实现。具体的操作流程如下:
“`php
beginTransaction();if ($parent_id) {
// 查询父级分类的祖先分类
$stmt = $dbh->prepare(‘SELECT ancestor_id FROM categories_closure WHERE descendant_id = :parent_id’);
$stmt->bindParam(‘:parent_id’, $parent_id);
$stmt->execute();
$ancestors = $stmt->fetchAll(PDO::FETCH_COLUMN);// 添加分类关系
$stmt = $dbh->prepare(‘INSERT INTO categories_closure (ancestor_id, descendant_id, depth) VALUES (:ancestor_id, :descendant_id, :depth)’);
foreach ($ancestors as $ancestor_id) {
$stmt->bindValue(‘:ancestor_id’, $ancestor_id);
$stmt->bindValue(‘:descendant_id’, $category_id);
$stmt->bindValue(‘:depth’, count(explode(‘,’, $ancestors)) + 1);
$stmt->execute();
}// 添加分类关系(自身和父级分类)
$stmt = $dbh->prepare(‘INSERT INTO categories_closure (ancestor_id, descendant_id, depth) VALUES (:category_id, :category_id, 0), (:parent_id, :category_id, 1)’);
$stmt->bindParam(‘:category_id’, $category_id);
$stmt->bindParam(‘:parent_id’, $parent_id);
$stmt->execute();
} else {
// 添加顶级分类
$stmt = $dbh->prepare(‘INSERT INTO categories_closure (ancestor_id, descendant_id, depth) VALUES (:category_id, :category_id, 0)’);
$stmt->bindParam(‘:category_id’, $category_id);
$stmt->execute();
}// 添加分类
$stmt = $dbh->prepare(‘INSERT INTO categories (name) VALUES (:name)’);
$stmt->bindParam(‘:name’, $name);
$stmt->execute();// 提交事务
$dbh->commit();
}
“`上述代码中的`addCategory`函数用于添加分类。函数首先查询父级分类的祖先分类,然后在分类关系表中添加分类之间的关系,其中祖先分类的深度是根据祖先分类的个数来确定的。最后在分类关系表中同时添加分类和父级分类的关系。具体操作都是使用MySQL的插入语句完成的。最后通过事务的方式来保证数据的一致性。
### 3. 查询分类
查询分类的过程就是根据分类之间的关系进行查询。可以使用递归的方式来实现查询每个分类的子分类的功能。具体的操作流程如下:
“`php
prepare($sql);
$stmt->bindParam(‘:ancestor_id’, $parent_id);
$stmt->bindParam(‘:depth’, $depth + 1);
$stmt->execute();
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);foreach ($categories as &$category) {
$category[‘name’] = str_repeat(‘-‘, $depth) . $category[‘name’];
$category[‘children’] = getCategories($category[‘id’], $depth + 1);
}return $categories;
}
“`上述代码中的`getCategories`函数接收两个参数,`parent_id`表示要查询的父级分类的ID,默认为`null`,表示所有顶级分类;`depth`表示当前分类的层级深度,默认为0。函数首先根据分类之间的关系查询子分类,然后使用递归的方式查询每个子分类的子分类,并将结果保存在每个分类的`children`字段中。同时根据分类的深度调整分类的名称,在名称前加上相应数量的横线。
### 4. 更新分类
更新分类的操作流程和添加分类类似,只是需要调整分类之间的关系。具体的操作流程如下:
“`php
prepare(‘SELECT * FROM categories WHERE id = :id’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();
$category = $stmt->fetch(PDO::FETCH_ASSOC);// 更新分类名称
$stmt = $dbh->prepare(‘UPDATE categories SET name = :name WHERE id = :id’);
$stmt->bindParam(‘:name’, $name);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();// 更新分类关系
$stmt = $dbh->prepare(‘UPDATE categories_closure SET depth = depth + :diff WHERE ancestor_id = :id’);// 查询分类的子分类
$stmt = $dbh->prepare(‘SELECT descendant_id FROM categories_closure WHERE ancestor_id = :id AND depth > 0’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();
$descendants = $stmt->fetchAll(PDO::FETCH_COLUMN);// 更新子分类的深度
$stmt = $dbh->prepare(‘UPDATE categories_closure SET depth = depth + :diff WHERE descendant_id = :descendant_id’);
foreach ($descendants as $descendant_id) {
$stmt->bindValue(‘:diff’, substr_count($category[‘name’], ‘-‘) – substr_count($name, ‘-‘));
$stmt->bindValue(‘:descendant_id’, $descendant_id);
$stmt->execute();
}
}
“`上述代码中的`updateCategory`函数用于更新分类的名称。函数首先查询分类的原始名称,然后更新分类的名称,最后根据分类名称的增加或减少来调整子分类的深度。
### 5. 删除分类
删除分类的操作流程也与添加分类类似,需要删除分类之间的关系。具体的操作流程如下:
“`php
prepare(‘SELECT descendant_id FROM categories_closure WHERE ancestor_id = :id’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();
$descendants = $stmt->fetchAll(PDO::FETCH_COLUMN);// 开启事务
$dbh->beginTransaction();// 删除分类关系
$stmt = $dbh->prepare(‘DELETE FROM categories_closure WHERE ancestor_id = :id OR descendant_id = :id’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();// 更新分类关系
$stmt = $dbh->prepare(‘UPDATE categories_closure SET depth = depth – 1 WHERE ancestor_id IN (‘ . implode(‘,’, $descendants) . ‘)’);
$stmt->execute();// 删除分类
$stmt = $dbh->prepare(‘DELETE FROM categories WHERE id = :id’);
$stmt->bindParam(‘:id’, $id);
$stmt->execute();2年前