English 中文(简体)
Nested join on same table (tree structure)
原标题:

My date is organized in tree structure.

The following applies (Oracle SQL syntax):

CREATE TABLE TREE
(
  NAME VARCHAR2(20),
  ID NUMBER(10, 0),
  PARENT NUMBER(10, 0)
)
;

INSERT INTO "TREE" (NAME, ID) VALUES ( a ,  1 );
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ( a.1 ,  2 ,  1 );
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ( a.2 ,  3 ,  1 );
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ( a.2.1 ,  4 ,  3 );
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ( a.2.2 ,  5 ,  3 );
INSERT INTO "TREE" (NAME, ID) VALUES ( b ,  6 );

I would like to return full tree by id, so for query :

select name, id <<<TODO LOGIC>> where id = 1

I would get

|  name  |  id  |
|  a     |  1   |
|  a.1   |  2   |
|  a.2   |  3   |
|  a.2.1 |  4   |
|  a.2.2 |  5   |

for a sub tree I would get:

select name, id <<<TODO LOGIC>> where id = 3

I would get

|  name  |  id  |
|  a.2   |  3   |
|  a.2.1 |  4   |
|  a.2.2 |  5   |

Where as, for flat entry b, it would get

select name, id <<<TODO LOGIC>> where id = 6

I would get

|  name  |  id  |
|  b     |  6   |

It seems that plain left out join queries fails to fulfill this purpose, or am I missing something?

The following query does return the full structure, but when starting to filter with where statements it fails.

select t1.id t1Id, t2.id t2Id, t1.name t1Name, t2.name t2Name from tree t1 left outer join tree t2 on t1.id = t2.parent
最佳回答

You can use start with - connect by syntax on Oracle. If I m not mistaken, it goes like this

select * from Tree t
start with t.ID = 1 connect by prior t.ID = t.Parent

But I have no Oracle to check it right away. Maybe its prior t.Parent = t.ID. Beware that it can be slow sometimes, use with caution.

Alternative is to create table to store all indirect relationship between nodes (not just a-a.1, but also a-a.2.1 and so on). You can fill it using PL/SQL recursive stored procedure. Two ways:

  1. Simple way is to make a procedure that will do complete refill of indirect table. You can call it before running reports.

  2. If you need instant effects, you should write refill procedure so that it will update indirect relationship just for one record in tree. Then you prohibit direct inserts and updates to Tree and force them to go via stored PL/SQL procedures (like InsertTree/UpdateTree) which in turn will call procedure to update table with indirect relationships.

问题回答

When you have a tree structure, you likely need a hierarchical query. Here it is:

 select t.*
   from tree t
connect by prior t.id = t.parent
  start with t.id = :id
  order siblings by t.id

See Hierarchical Queries for details.

You could use union for this, and you need to limit the depth of the tree to make it possible to select it in one query.

SELECT id, name
FROM TREE as node
WHERE 
  node.id = :id
UNION
SELECT child1.id, child1.name
FROM TREE as node
  inner join TREE as child1 on node.id = child1.parent
WHERE 
  node.id = :id
UNION
SELECT child2.id, child2.name
FROM TREE as node
  inner join TREE as child1 on node.id = child1.parent
  inner join TREE as child2 on child1.id = child2.parent
WHERE 
  node.id = :id

The problem here is, SQL is very bad in recursion (while relational structures are actually great in this).

To make it fully dynamic, use a query for each level in the tree, or use a database engine specific SQL extension if there is anything usable.





相关问题
Export tables from SQL Server to be imported to Oracle 10g

I m trying to export some tables from SQL Server 2005 and then create those tables and populate them in Oracle. I have about 10 tables, varying from 4 columns up to 25. I m not using any constraints/...

Connecting to Oracle 10g with ODBC from Excel VBA

The following code works. the connection opens fine but recordset.recordCount always returns -1 when there is data in the table. ANd If I try to call any methods/properties on recordset it crashes ...

How to make a one to one left outer join?

I was wondering, is there a way to make a kind of one to one left outer join: I need a join that matches say table A with table B, for each record on table A it must search for its pair on table B, ...

Insert if not exists Oracle

I need to be able to run an Oracle query which goes to insert a number of rows, but it also checks to see if a primary key exists and if it does, then it skips that insert. Something like: INSERT ALL ...

How can I store NULLs in NOT NULL field?

I just came across NULL values in NOT-NULL fields in our test database. How could they get there? I know that NOT-NULL constraints can be altered with NOVALIDATE clause, but that would change table s ...

Type reference scope

I m studying databases and am currently working on a object-relational DB project and I ve encountered a small problem with the number of possible constraints in an object table. I m using "Database ...

OracleParameter and DBNull.Value

we have a table in an Oracle Database which contains a column with the type Char(3 Byte). Now we use a parameterized sql to select some rows with a DBNull.Value and it doesn t work: OracleCommand ...

热门标签