2009-10-26 8 views
3

Допустим, у меня есть таблица областей (id, parentId, name, path).Sql Получить все дочерние элементы родителя

Учитывая идентификатор, я хотел бы получить все детские (дети детей включены, рекурсивно) данной области.

Я храню на пути путь от родителей к ребенку.

Пример:

1 NULL New York /1/ 
2 1 BRONX /1/2/ 
3 1 MANH  /1/3/ 
4 3 UpWest /1/3/4/ 
5 3 MidEast /1/3/5/ 

Так что, когда просят за то, что дети из Нью-Йорка, запрос должен возвращать Бронкс, Мань, upwest и Mideast. и не только бронкс и манх.

+2

Shoud the MidEast path be '/ 1/3/5 /'? –

+0

да исправил его, thx – pdiddy

ответ

3

Вернет все районы, являющиеся дочерним городом города с идентификатором 1 (например, Нью-Йорк). Вы можете изменить этот номер в любой другой город, чтобы вернуть его дети тоже

select * from areas where path like '%/1/%' 
+0

отредактировал для обработки более 9 строк :) – Trevor

2

Вы можете использовать

SELECT * FROM Areas WHERE Path LIKE '%/1/%' 

если вы путь хранится

0

Посмотрите на START WITH и CONNECT BY в Oracle SQL. таким образом вы можете выбрать данные с иерархическими отношениями (древовидными).

0

Не знаю, что базы данных вы используете: Если SQL Server, используйте Common Table Expression (CTE)

В противном случае,

Вам нужен какой-то код или хранимую процедуру .. Использование psuedoCode

Assuming @Parent is Primary key of Area record you want children of... 
    --Create Temp table (Does your DB have temp Tables) of Keys 
    -- Say it's called 'Children' 
    -- -- make this a temmp table... 
    -- In SQL Server syntax uses a #. 
    -- Create Table #Table... (or use table variable Declare @Children Table ...), 
    -- Oracle, MySql have their own syntax... 


    Create Table Children 
    (PK Integer Primary Key Not Null) 
    -- ------------------------- 
    Insert Children(PK) 
    Select PK From Area 
    Where Parent = @Parent 
    -- ----------------------- 
    While Exists (Select * From 'Children' As C 
       Where Exists 
        (Select * From Area 
        Where parent = C.PK 
         And PK Not In 
          (Select PK From 'Children'))) 
     Begin 
      Insert Children(PK) 
      Select PK From Area 
      Where Parent In (Select PK From Children) 
       And PK Not In (Select PK From Children) 
     End 

    --Then join temp table to Area table and return results 

    Select a.* From Area a 
     Join Children C On C.PK = A.PK 
0

Попробуйте это:

declare @id int 
select @id = 1; 

with CustParent (ParentID,ChildID) 
      as 
      (
       select o.ParentID, o.ChildID 
       from Customer o 
       where o.ID = @id 
       union all 
       select cpc.ParentID ,cpc.ID 
       from Customer cpc 
       inner join CustParent cp on cp.ChildID = cpc.ParentID 
      ) 

Select Customer.ChildID, Customer.ParentID 
from Customer 
inner join CustParent cp on cp.ChildID = Customer.ChildID 

I Реус Это все время.

1

Если у вас есть глубина набор чисел, который вы знаете, вы никогда не будете идти глубже, чем это будет делать то, что вы хотите:

select * from areas a1 
join areas a2 on a1.id = a2.parent 
join areas a3 on a2.id = a3.parent 
join areas a4 on a3.id = a4.parent 
join areas a5 on a4.id = a5.parent 
where a1 = 1; --or whatever value you're searching for. 

Edit: Однако, если у вас уже есть сохранен путь (который я до сих пор не замечали), путь, как «%/1 /%», является лучшим решением.

0

SQLite:

SELECT * FROM Areas where path like (SELECT path || '%' FROM Areas WHERE area="New York")

1

В MySQL:

SELECT * 
FROM Areas ap 
JOIN Areas ac 
ON  ac.path > ap.path 
     AND ac.path < CONCAT(ap.path, ':') 
WHERE ap.id = 1 

В PostgreSQL и Oracle:

SELECT * 
FROM Areas ap 
JOIN Areas ac 
ON  ac.path > ap.path 
     AND ac.path < ap.path || ':' 
WHERE ap.id = 1 

В SQL Server:

SELECT * 
FROM Areas ap 
JOIN Areas ac 
ON  ac.path > ap.path 
     AND ac.path < ap.path + ':' 
WHERE ap.id = 1 

В отличие от LIKE (не каламбур), это будет использовать индекс path.

+0

Можете ли вы объяснить мне, как это работает? Я не получаю ':' ??? – pdiddy

+0

':' является первым символом ASCII после цифр: '9' имеет' ASCII' код '57',': 'имеет' ASCII' код '58'. Это грубый фильтр, основанный на предположении, что у вас нет ничего, кроме цифр и косых черт на вашем пути. – Quassnoi

Смежные вопросы