简体   繁体   中英

SQL Tree Structure

I am new to this topic (ie tree structure) in SQL. I have gone through different sources but still not clear.

Here in my case, I have a table which I have attached herewith.

在此处输入图片说明

Now here first, I have to retrieve a Full Tree for “OFFICE”.

Also i have to find all the leaf nodes (those with no Children) in the attached hierarchical data.

Please provide the answers with detail explanation. Thanks in advance.

Now here first, I have to retrieve a Full Tree for “OFFICE”.

How do you want to represent your tree? What you have posted can already count as a tree.

Also I have to find all the leaf nodes (those with no Children) in the attached hierarchical data.

TSQL:

select * 
from table outer 
where id not in (select id 
                 from table inner 
                 where inner.parent = outer.id)

The inner select will give you all ids pointing to a certain parent. The outer select will give you all nodes for which the inner select yields no results.

There is a pattern design called "hardcoded trees" that can be usefull for this purpose. 在此处输入图片说明

Then you can use this query for finding a parent for each child

SELECT level1ID FROM Level2entity as L2 WHERE level2ID = :aLevel2ID

Or this one for finding the children for each parent:

SELECT level1ID FROM Level2entity as L2 WHERE level2ID = :aLevel2ID

If you can afford a little bit of pre-processing time, then a classic solution to this problem would be to use nested sets .

CREATE TABLE node (
    id INTEGER NOT NULL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    parent_id INTEGER DEFAULT NULL,
    seq_min INTEGER NOT NULL,
    seq_max INTEGER NOT NULL
); 

Assuming, that you use some kind of in-memory data structure like

class Node:
   def __init__(self, id, name, children=()):
      self.id = id
      self.name = name
      self.children = list(children)

to represent the tree nodes in memory, we can then define

def assign_sequence_numbers(root_node):
    def recurse(counter, node):
        node.seq_min = counter
        node.seq_max = reduce(recurse, node.children, 1 + counter)
        return node.seq_max
    return recurse(1, root_node)

which does a pre-order traversal over the tree, which assignes two additional numbers to each node:

The seq_min value becomes an alternate unique integer key for each node. Also, all direct children (and indirect descendants) of a node will have a seq_min value, which is larger than the value assigned to the node itself.

The seq_max value is simply an upper boundary for the seq_min values of all descendant nodes.

Example: Consider the following tree

Root
 |
 +--- Category1
 |      |
 |      +--- Category1.1
 |      |
 |      `--- Category1.2
 |
 `--- Category2

Using the function defined above, we get

Root [min=1, max=6]
 |
 +--- Category1 [min=2, max=5]
 |      |
 |      +--- Category1.1 [min=3, max=4]
 |      |
 |      `--- Category1.2 [min=4, max=5]
 |
 `--- Category2 [min=5, max=6]

Observe, that for every node, the min value is always <= the min value of all descendants and the max value is always > the max value of all descendants. So, to find the descendants of Root and that node itself (ie, get the entire tree), we'd do:

SELECT * FROM node 
WHERE seq_min >= 1 /* i.e., seq_min(Root) */
AND seq_min < 6    /* i.e., seq_max(Root) */

To get the descendants of Category1 (and that node itself)

SELECT * FROM node 
WHERE seq_min >= 2 /* i.e., seq_min(Category1) */
AND seq_min < 5    /* i.e., seq_max(Category2) */

The drawback of this method is, that in principle, you will have to re-assign the seq_xxx numbers for all nodes, if you make changes to the tree, ie, insert new nodes or delete old ones. This is often not a problem, at least if changes to the tree structure are infrequent and the tree is sufficiently small.

As ITGenius already linked to that answer : if your database supports it, using common table expressions is another possibility, which avoids the pre-processing step and is also more resilient in the face of changes to the tree structure.

(I did not test any of the code given in this answer. You might need to apply a few fixes here and there; in particular, if your project's language of choice is not python...)

You didn't specify your DBMS but with standard SQL (supported by all modern DBMS ) you can easily do a recursive query to get the full tree:

with recursive full_tree as (
  select id, name, parent, 1 as level
  from departments
  where parent is null
  union all 
  select c.id, c.name, c.parent, p.level + 1
  from departments c
    join full_tree p on c.parent = p.id
)
select *
from full_tree;

If you need a sub-tree, just change the starting condition in the common table expression. To get eg all "categories":

with recursive all_categories as (
  select id, name, parent, 1 as level
  from departments
  where id = 2 --- << start with a different node 
  union all 
  select c.id, c.name, c.parent, p.level + 1
  from departments c
    join all_categories p on c.parent = p.id
)
select *
from all_categories;

Getting all leafs is straightforward: it's all nodes where their ID does not appear as a parent :

select *
from departments
where id not in (select parent
                 from departments
                 where parent is not null);

SQLFiddle example: http://sqlfiddle.com/#!15/414c9/1


Edit after DBMS has been specified.

Oracle does support recursive CTEs (although you need 11.2.x for that) you just need to leave out the keyword recursive . But you can also use the CONNECT BY operator:

select id, name, parent, level
from departments
start with parent is null
connect by prior id = parent;

select id, name, parent, level
from departments
start with id = 2
connect by prior id = parent;

SQLFiddle for Oracle: http://sqlfiddle.com/#!4/6774ee/3

See the manual for details: https://docs.oracle.com/database/121/SQLRF/queries003.htm#i2053935

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM