mysql子表过滤父纪录,查询以获取带有子记录的父记录,然后是mysql中的下一个父子记录...

I have data in the following format in the Names table in database:

ID | Name | ParentID

1 | Parent 1 | 0

2 | Parent 2 | 0

3 | Parent 1 Child 1 | 1

4 | Parent 2 Child 1 | 2

5 | Parent 1 Child 1 Child | 3

6 | Parent 2 Child 1 Child 1 | 4

7 | Parent 2 Child 1 Child 2 | 4

The ParentID column is having data from ID column as parent record. ParentID with 0 value indicates root items. I need to write a query to get data in the following order:

ID | Name | ParentID

1 | Parent 1 | 0

3 | Parent 1 Child 1 | 1

5 | Parent 1 Child 1 Child | 3

2 | Parent 2 | 0

4 | Parent 2 Child 1 | 2

6 | Parent 2 Child 1 Child 1 | 4

7 | Parent 2 Child 1 Child 2 | 4

I need to get the root record(record with ParentID as 0) followed by all the child and sub-children of this root record and then get the next root record followed by child and sub-children of the this root record and so on.

解决方案

The solution I propose here uses the concept of materialized path. The following is an example of materialized paths using your sample data. I hope it helps you to understand materialized path concept:

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

| ID | Name | ParentID | MaterializedPath |

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

| 1 | Parent 1 | 0 | 1 |

| 2 | Parent 2 | 0 | 2 |

| 4 | Parent 2 Child 1 | 2 | 2.4 |

| 6 | Parent 2 Child 1 Child 1 | 4 | 2.4.6 |

| 7 | Parent 2 Child 1 Child 2 | 4 | 2.4.7 |

| 3 | Parent 1 Child 1 | 1 | 1.3 |

| 5 | Parent 1 Child 1 Child | 3 | 1.3.5 |

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

Each node N has a materialized path, this path tells you the way to go from the root node to the node N. It can be build concatenating the node id's. For example, to reach node 5 starting from its root node, you visit node 1, node 3, and node 5, so node 5 materialized path is 1.3.5

Coincidentally, the order you are looking for can be achieved ordering by the materialized path.

On the previous example, materialized paths are buit concatenating strings, but I prefer binary concatenation for a number of reasons.

To build the materialized paths you need the following recursive CTE:

CREATE TABLE Tree

(

ID int NOT NULL CONSTRAINT PK_Tree PRIMARY KEY,

Name nvarchar(250) NOT NULL,

ParentID int NOT NULL,

)

INSERT INTO Tree(ID, Name, ParentID) VALUES

(1, 'Parent 1', 0),

(2, 'Parent 2', 0),

(3, 'Parent 1 Child 1', 1),

(4, 'Parent 2 Child 1', 2),

(5, 'Parent 1 Child 1 Child', 3),

(6, 'Parent 2 Child 1 Child 1', 4),

(7, 'Parent 2 Child 1 Child 2', 4)

GO

WITH T AS

(

SELECT

N.ID, N.Name, N.ParentID, CAST(N.ID AS varbinary(512)) AS MaterializedPath

FROM

Tree N

WHERE

N.ParentID = 0

UNION ALL

SELECT

N.ID, N.Name, N.ParentID, CAST( T.MaterializedPath + CAST(N.ID AS binary(4)) AS varbinary(512) ) AS MaterializedPath

FROM

Tree N INNER JOIN T

ON N.ParentID = T.ID

)

SELECT *

FROM T

ORDER BY T.MaterializedPath

Result:

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

| ID | Name | ParentID | MaterializedPath |

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

| 1 | Parent 1 | 0 | 0x00000001 |

| 3 | Parent 1 Child 1 | 1 | 0x0000000100000003 |

| 5 | Parent 1 Child 1 Child | 3 | 0x000000010000000300000005 |

| 2 | Parent 2 | 0 | 0x00000002 |

| 4 | Parent 2 Child 1 | 2 | 0x0000000200000004 |

| 6 | Parent 2 Child 1 Child 1 | 4 | 0x000000020000000400000006 |

| 7 | Parent 2 Child 1 Child 2 | 4 | 0x000000020000000400000007 |

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

The above recursive CTE starts with the root nodes. Calculating the materialized path for a root node is trivially straightforward, it's the ID of the node itself. On the next iteration the CTE joins root nodes with its child nodes. The materialized path for a child node CN is the concatenation of the materialized path of its parent node PN and the id of node CN. Subsequent iterations advance one level down on the tree until the leaf nodes are reached.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值