注意:此问题已更新以反映我们目前正在使用 MySQL,这样做后,我想看看如果我们切换到支持 CTE 的数据库会更容易。
我有一个带有主键id和外键的自引用表parent_id。
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| parent_id | int(11) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| notes | text | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)
给定 a name,如何查询顶级父级?
给定 a name,如何查询id …
是否有人在实际生产中使用 HierarchyId 使用合理大小的表,超过几千行?它可靠/性能好吗?到目前为止,我还没有发现任何与供应商无关的人推荐它,并且 Paul Nielsen在这里建议不要使用它。
您在实际生产系统中使用 HierarchyId 的经验是什么?
当您选择 HierarchyId 而不是其替代品时,您使用了哪些标准?
我必须跟踪 SQL Server 2008 R2 中的数据。SQLFiddle
架构:
创建表 [dbo].[ICFilters](
[ICFilterID] [int] IDENTITY(1,1) 非空,
[ParentID] [int] NOT NULL DEFAULT 0,
[FilterDesc] [varchar](50) NOT NULL,
[Active] [tinyint] NOT NULL DEFAULT 1,
约束 [PK_ICFilters] 主键聚集
( [ICFilterID] ASC ) 与
PAD_INDEX = 关闭,
STATISTICS_NORECOMPUTE = 关闭,
IGNORE_DUP_KEY = 关闭,
ALLOW_ROW_LOCKS = 开,
ALLOW_PAGE_LOCKS = 开
) 在 [主要]
) 在 [主要]
INSERT INTO [dbo].[ICFilters] (ParentID,FilterDesc,Active)
价值观
(0,'产品类型',1),
(1,'ProdSubType_1',1),
(1,'ProdSubType_2',1),
(1,'ProdSubType_3',1),
(1,'ProdSubType_4',1),
(2,'PST_1.1',1),
(2,'PST_1.2',1),
(2,'PST_1.3',1),
(2,'PST_1.4',1),
(2,'PST_1.5',1),
(2,'PST_1.6',1),
(2,'PST_1.7',0),
(3,'PST_2.1',1),
(3,'PST_2.2',0),
(3,'PST_2.3',1),
(3,'PST_2.4',1), … 有没有办法在 SQL 中遍历树数据?我知道connect by在 Oracle 中,但是在其他 SQL 实现中还有另一种方法吗?我问是因为使用connect by比编写循环或递归函数来为每个结果运行查询更容易。
由于有些人似乎对短语“树数据”感到困惑,我将进一步解释:我的意思是关于具有parent_id或类似字段的表,该字段包含来自同一表中另一行的主键。
问题来自我在 Oracle 数据库中处理以这种方式存储的数据的经验,并且知道connect by其他 DBMS 中没有实现。如果要使用标准 SQL,则必须为每个想要向上的父表创建一个新表别名。这很容易失控。
我需要创建一些涉及层次结构的测试数据。我可以让它变得简单并做几个CROSS JOINs,但这会给我一个完全统一/没有任何变化的结构。这不仅看起来很乏味,而且测试数据缺乏变化有时会掩盖原本会发现的问题。所以,我想生成一个遵循以下规则的非统一层次结构:
WHILE循环可以很容易地做到这一点,但首选是找到一种基于集合的方法。一般而言,生成测试数据没有生产代码对效率的要求,但尝试基于集合的方法可能会更具教育意义,并有助于在未来找到基于集合的方法来解决问题。因此WHILE,不排除循环,但只有在不可能使用基于集合的方法时才能使用循环。我正在玩 HierarchyId,但我还没有想出一种基于集合的方法来执行以下操作:
这个问题与我之前的问题有关,我怀疑使用 HierarchyId 完成这两个任务的唯一方法是一次一个节点或一个级别。如果我使用的是物化路径,那么这两个操作都可以通过一个(且简单的)基于集合的命令轻松完成。
我错过了什么?
编辑:我也错过了移动子树的方法,但我是从 Mikael Eriksson 的评论中学到的
假设我们有一个对自身有外键约束的表,如下所示:
CREATE TABLE Foo
(FooId BIGINT PRIMARY KEY,
ParentFooId BIGINT,
FOREIGN KEY([ParentFooId]) REFERENCES Foo ([FooId]) )
INSERT INTO Foo (FooId, ParentFooId)
VALUES (1, NULL), (2, 1), (3, 2)
UPDATE Foo SET ParentFooId = 3 WHERE FooId = 1
Run Code Online (Sandbox Code Playgroud)
该表将有以下记录:
FooId ParentFooId
----- -----------
1 3
2 1
3 2
Run Code Online (Sandbox Code Playgroud)
在某些情况下,这种设计可能有意义(例如典型的“员工-老板-员工”关系),并且无论如何:我处于我的模式中有这种情况的情况。
不幸的是,这种设计允许数据记录中的循环,如上例所示。
那么我的问题是:
对于这个问题的第 (2) 部分,可能需要提及的是,我希望我的表中只有数百或在某些情况下可能有数千条记录,通常嵌套的深度不会超过大约 5 到 10 级。
附注。微软 SQL Server 2008
2012 年 3 月 14 日更新
有几个很好的答案。我现在已经接受了帮助我理解提到的可能性/可行性的那个。不过,还有其他几个很好的答案,其中一些还提供了实施建议,因此,如果您带着相同的问题来到这里,请查看所有答案;)
这是为了构建我们将用于报告的一些视图。
我有一个位置表,关键字段是 "location" 和 "parent"。
这两个字段创建的结构在级别上是沿着公司名称 --> 校园名称 --> 建筑物名称 --> 楼层名称 --> 房间名称。在这种情况下,公司名称保持不变,校园名称保持不变。
位置的结构通常如下所示:
+-----------+
| Org. Name |
+-----+-----+
|
+-----v-----+
+--------------------+|Campus Name|+---+--+-------------+
| +--+--------+ | |
| | | |
| | | |
+--+-----+ +------+-+ +--+----+ +---+---+
+--+| BLDG-01|+--+ | BLDG-02| |BLDG-03| |Grounds|
| +--------+ | +--------+ +-------+ +-------+
+-+------+ +-----+--+
|Floor-01| |Basement+-------+
+-+------+ +--------+ |
| |
| |
| +----------+ +-------+--+
+-+Room 1-001| |Room B-002|
+----------+ +----------+
Run Code Online (Sandbox Code Playgroud)
每个位置都链接回其父位置,最终是组织名称。目前,只有一个组织和一个校区。
我想使用 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)
或者,有没有更好的方法来处理这个问题?你看,目前我必须运行大量查询才能找到计数,而我宁愿一次性完成。
内置的hierarchyid是一个CLR,它以高效的二进制形式存储路径,并提供其他有用的功能。
不幸的是,所表示的路径的深度是有限的,对于二叉树来说大约是 1427。对于必然会达到此限制的复杂现有应用程序,我想增加该限制。我不想改变类型的界面。我不相信我可以改变类型的接口而不将细微的错误引入所有必须更改的代码中。
我可以(理论上)创建一个“binhierarchyid”CLR UDT,它实现与hierarchyid 相同的接口,但只支持二叉树。这应该让我获得 ~7000 的深度,同时仍然保持在 900 字节的限制内。不知道这将是一项多大的事业。
这个hierarchyid CLR的来源是否在某处可用,以便我可以基于它创建自己的支持更深层次的结构?