有没有办法在 SQL 中遍历树数据?我知道connect by
在 Oracle 中,但是在其他 SQL 实现中还有另一种方法吗?我问是因为使用connect by
比编写循环或递归函数来为每个结果运行查询更容易。
由于有些人似乎对短语“树数据”感到困惑,我将进一步解释:我的意思是关于具有parent_id
或类似字段的表,该字段包含来自同一表中另一行的主键。
问题来自我在 Oracle 数据库中处理以这种方式存储的数据的经验,并且知道connect by
其他 DBMS 中没有实现。如果要使用标准 SQL,则必须为每个想要向上的父表创建一个新表别名。这很容易失控。
基于Traversing tree-like data in arelational database using SQL问题,我想知道如何在考虑物理含义的情况下经常使用的方式描述关系数据库上的树状数据?
我假设 RDBMS 除了常规 SQL ANSI 或常见可用功能之外没有特殊功能来处理它。
毫无疑问,我总是对 MySQL 和 PostgreSQL 以及最终的 SQLite 感兴趣。
我想使用 MySQL 在一个查询中执行以下操作:
如何在一个查询中完成此操作?如果您需要更多信息,请告诉我,我很乐意为您提供帮助。我不是创建问题的专家,所以请告诉我您需要什么更多信息。
这是我现在正在做的一个例子:
select id from messages where parent_id=0
Run Code Online (Sandbox Code Playgroud)
进而
select count(id) from messages where parent_id={{previously_chosen_id}}
Run Code Online (Sandbox Code Playgroud)
如何获得一次性查询?就像是...
select id, count(records where parent_id=the id we just asked for)
Run Code Online (Sandbox Code Playgroud)
或者,有没有更好的方法来处理这个问题?你看,目前我必须运行大量查询才能找到计数,而我宁愿一次性完成。
我正在做决策树数据库的概念模型。目标是存储任何决策树。
我有四种实体类型:DecisionTree、Node、Branch 和 Leaf。
决策树示例:
图 1 提供了一个决策树及其相关规则的示例,其中 p(Class #i) 是对象属于 Class #i 的概率。
SQL 数据库中的树示例:
决策树的表示:
我的概念设计在以下实体关系图 (ERD) 中表示:
所以,问题是:如何将节点、分支和叶与决策树关联起来?
我试图在 PostgreSQL (8.4) 中表示树结构,以便能够查询从根到给定节点的路径或查找子分支中的所有节点。
下面是一个测试表:
CREATE TABLE tree_data_1 (
forest_id TEXT NOT NULL,
node_id TEXT NOT NULL,
parent_id TEXT,
node_type TEXT,
description TEXT,
PRIMARY KEY (forest_id, node_id),
FOREIGN KEY (forest_id, parent_id) REFERENCES tree_data_1 (forest_id, node_id)
);
CREATE INDEX tree_data_1_forestid_parent_idx ON tree_data_1(forest_id, parent_id);
CREATE INDEX tree_data_1_forestid_idx ON tree_data_1(forest_id);
CREATE INDEX tree_data_1_nodeid_idx ON tree_data_1(node_id);
CREATE INDEX tree_data_1_parent_idx ON tree_data_1(parent_id);
Run Code Online (Sandbox Code Playgroud)
每个节点由(forest_id, node_id)
(在另一个林中可以有另一个具有相同名称的节点)标识。每棵树都从一个根节点(其中parent_id
为空)开始,尽管我只希望每个森林都有一个。
这是使用递归 CTE 的视图:
CREATE OR REPLACE VIEW tree_view_1 AS
WITH RECURSIVE rec_sub_tree(forest_id, node_id, parent_id, depth, path, cycle) …
Run Code Online (Sandbox Code Playgroud) 我正在尝试找出零售商的数据模型。
该零售商在全国拥有多家商店,它们使用以下层次结构进行建模:
Channel -> Zone -> City -> Store
Run Code Online (Sandbox Code Playgroud)
每家商店都包含几篇文章。每篇文章都有这样的属性
现在,零售商可以在层次结构中的任何级别设置这些属性。考虑以下情况:
到目前为止,他们已经使用 RDBMS 对其进行建模,方法是在层次结构的顶部定义全局规则,并将异常作为单独的行单独调用。比如说,价格表将在渠道级别为文章设置价格,任何级别的任何更改都将单独指定。显然,这在获取商店级别的属性时效率不高。
样本数据
假设 Channel、Zone、City 和 Store 统称为实体。频道的 ID 范围 >= 4000,区域 >= 3000,城市 >= 2000,商店范围从 1 到 1000。
下面给出了层次关系数据的一个子集:
Channel | Zone | City | Store |
----------+----------+------------------
4001 | 3001 | 2001 | 13 |
4001 | 3001 | 2001 | 14 |
4001 | 3001 | 2002 | 15 |
4001 | 3002 | 2003 | 16 | …
Run Code Online (Sandbox Code Playgroud) 我在 PostgreSQL 9.4 中存储了一个典型的树结构作为邻接列表:
gear_category (
id INTEGER PRIMARY KEY,
name TEXT,
parent_id INTEGER
);
Run Code Online (Sandbox Code Playgroud)
以及附加到类别的项目列表:
gear_item (
id INTEGER PRIMARY KEY,
name TEXT,
category_id INTEGER REFERENCES gear_category
);
Run Code Online (Sandbox Code Playgroud)
任何类别都可以附加装备物品,而不仅仅是树叶。
出于速度原因,我想预先计算有关每个类别的一些数据,我将使用这些数据来生成物化视图。
期望的输出:
speedy_materialized_view (
gear_category_id INTEGER,
count_direct_child_items INTEGER,
count_recursive_child_items INTEGER
);
Run Code Online (Sandbox Code Playgroud)
count_recursive_child_items
是附加到当前类别或任何子类别的 GearItems 的累积数量。每个类别应占一行,任何为 0 的计数都为 0。
为了计算这个,我们需要使用递归 CTE 来遍历树:
WITH RECURSIVE children(id, parent_id) AS (
--base case
SELECT gear_category.id AS id, gear_category.parent_id AS parent_id
FROM gear_category
WHERE gear_category.id = 37 -- setting this to id includes current object …
Run Code Online (Sandbox Code Playgroud) 我想以某种格式表示我的目录结构(目前我只是使用 JSON。)
这是示例 JSON 的外观。对于那些好奇的人,它是使用 unix tree 命令生成的:tree /path/to/folder -J --noreport -h
.
{
...
"type":"directory",
"name":"dev",
"size":4096,
"contents":[
{"type":"directory","name":"protocols","size":4096, "contents":[]},
{"type":"file","name":"architecture.txt","size":4716},
{"type":"file","name":"exceptions.py","size":31263},
{"type":"file","name":"models.js","size":101882},
{"type":"file","name":"proxy.cpp","size":29097},
{"type":"file","name":"keylogfile.xyz","size":7889},
{"type":"file","name":"Readme.txt","size":8857},
]
...
}
Run Code Online (Sandbox Code Playgroud)
所以这只是将某些路径的整个文件夹结构表示为 JSON。
我可以有许多这样的单独 JSON 文件,每个文件代表一个目录树。这些文件之间没有关联/链接。
在标准 Windows“C:\”分区上运行 tree 命令时,我得到一个大约 30 MB 的 JSON 文件。所以我认为我们可以假设用户上传的最大文件大小约为 100 MB。
存储文件后,这些是我计划对文件进行的操作:
ls
在这条路径上做的事情。)note
。2 和 3 是我最希望发生的操作。
以下是我提出的存储这些数据的方法:
没有数据库:
/home/forest/<uuid>.json
)没有 SQL
我正在学习动态树结构组织以及如何设计数据库。
考虑具有以下特征的 DBMS:
二级索引定义在 8 字节的页面上。可以用三级 B 树索引的最大记录数是多少?并且具有三级 B+树?
以下是这些树的两个示例:
我读过那个
B+树比B树浅。因为除了最后一个之外,每个叶节点中只有表示为k的最高键的集合存储在非叶节点中,组织为 B 树。关系 DBMS 内部,第 5 章:动态树结构组织,第 46 页
因此有一个区别,我们存储在 B 树的节点中的东西存储在 B+ 树的叶子中。因此,在我看来,它是(m-1) h(m是顺序,h是高度),因为每个节点最多包含另一个节点的 (m-1) 个键。但这与字节数无关。
然而我在上面提到的书中找到了下表:
因此它会是 20 3.7条记录吗?
对于他们来说,只要有一些值存储在节点中,我就必须除以节点数。而我被困在那里。
我有一个客户的非二叉树,我需要为给定节点获取树中的所有 ID。
该表非常简单,只是一个带有父ID和子ID的连接表。这是我存储在数据库中的树的表示。
在这个例子中,如果我搜索节点 17,我需要返回 14-17。如果我搜索 11,我需要返回 1-6-5-4-8-11-12-7-2-10-3。
顺序并不重要。在将子节点添加到节点时,我只需要 ID 以避免循环。
我创建了这个查询。祖先部分工作正常,我检索了所有父节点,但对于后代我有一些麻烦。我只能检索树的某些部分。例如,对于节点 11,我检索 4-10-6-11-7-8,因此树的所有正确部分都丢失了。
WITH RECURSIVE
-- starting node(s)
starting (parent, child) AS
(
SELECT t.parent, t.child
FROM public.customerincustomer AS t
WHERE t.child = :node or t.parent = :node
)
,
ancestors (parent, child) AS
(
SELECT t.parent, t.child
FROM public.customerincustomer AS t
WHERE t.parent IN (SELECT parent FROM starting)
UNION ALL
SELECT t.parent, t.child
FROM public.customerincustomer AS t JOIN ancestors AS a ON t.child = a.parent
),
descendants (parent, …
Run Code Online (Sandbox Code Playgroud) tree ×10
hierarchy ×3
postgresql ×3
cte ×2
erd ×2
btree ×1
count ×1
index ×1
max ×1
mysql ×1
optimization ×1
performance ×1
recursive ×1