mysql - MySQL 中的分层数据

标签 mysql join hierarchical-data

我的 MySQL 数据库中有一种树状结构。

我有一个包含类别的数据库,每个类别都有一个子类别。我将所有类别保存在一张表中,因此列如下所示:

*categories table*
id | name  | parent_id
1  | Toys  | 0
2  | Dolls | 1
3  | Bikes | 1

我数据库中的每个项目都分配给这些类别之一:

*items table*
item   | category_id
barbie | 2
schwinn| 3

问题是,如果有人想查看所有玩具(父类别),从项目数据库中获取信息的最佳方式是什么?我知道的唯一方法是做类似的事情

SELECT * 
FROM items 
WHERE category_id = 2 
JOIN SELECT * 
     FROM items 
     WHERE category_id = 3
     etc... 

但如果我在玩具下有 10 个类别,那么我必须执行 10 次连接和查询。

有没有更好的方法来处理这个问题?

最佳答案

您希望获得父 ID:

所以假设你得到了

set @parentId = 1 /*toys*/

select 
  *
from
  Items i
inner join Categories c on c.id = i.categoryId
where
  c.parentId = @parentId

这将为您提供您想要的项目 - 有一个主要的设计缺陷:它不能处理多个层次的分层类别。

假设您有这个类别表:

*Categories table*
id | name    | parentId
1  | Toys    | 0
2  | Dolls   | 1
3  | Bikes   | 1
4  | Models  | 2
5  | Act.Fig.| 2
6  | Mountain| 3
7  | BMX     | 3

还有元素:

*items table*
item   | category_id
Barbie | 4
GIJoe  | 5
Schwinn| 6
Huffy  | 7

获取所有相关项目的唯一方法是进行自连接:

select 
  *
from
  Items i 
inner join Categories c on c.id = i.categoryId
inner join Categories c2 on c.parentId = c2.id
where
  c2.parentId = @parentId

这种模式是不可扩展的——因为你可以有多个层次的层次结构。

处理层次结构的一种常见方法是构建一个“扁平化”表:将每个节点与其所有后代链接起来的行。

除了类别表之外,您还构建了第二个表:

*CategoriesFlat table*  The Name column is here only for readability
id | name    | parentId
1  | Toys    | 1
-----------------
2  | Dolls   | 1
2  | Dolls   | 2
-----------------
4  | Models  | 1
4  | Models  | 2
4  | Models  | 4
5  | Act.Fig.| 1
5  | Act.Fig.| 2
5  | Act.Fig.| 5
-----------------
3  | Bikes   | 1
3  | Bikes   | 3
-----------------
6  | Mountain| 1
6  | Mountain| 3
6  | Mountain| 6
7  | BMX     | 1
7  | BMX     | 3
7  | BMX     | 7

所以你可以写:

select 
  *
from
  Items i
inner join CategoriesFlat c on c.id = i.categoryId
where
  c.parentId = @parentId

并获取所有相关的类别和项目。

这是 great slideshow about SQL anti-patterns以及他们的解决方案。 (SQL 中的分层数据是一种反模式,但不要灰心——我们都会遇到这种情况)

关于mysql - MySQL 中的分层数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1085287/

相关文章:

mysql - MS Office 不再作为 BLOB 工作

java - 使用 @ManyToMany 关联连接三个表

sql - 如何只选择满足条件的第一行?

postgresql - 如何在 PostgreSQL 中使用与语言相关的数据进行分层查询

javascript - 在javascript中将平面数组转换为json

mongodb - MongoDB 中 "Parent Links"树上的 MapReduce

python - PyMYSQL - 选择值可以为 NULL 的位置

mysql - MariaDB设置: Access denied for user 'root' @'ma' (using password: YES)

mysql - 使用 LINQ/lambda .net MVC 从表中选择某些列的所有数据?

cakephp - 如何创建使用子查询的联接?