SQL Obter todos os filhos de um pai
Pergunta
Vamos dizer que eu tenho um Áreas de Tabela (id, parentId, nome, caminho).
Dada uma Id, eu gostaria de obter todas crianças (filhos de crianças incluídas, de forma recursiva) da área dada.
Eu faço loja no caminho o caminho dos pais para a criança.
Exemplo:
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/
Assim, quando pedir o que são os filhos de Nova York, a consulta deve retornar Bronx, manh, upwest e médio oriente. e não só Bronx e manh.
Solução
retornará todas as áreas que são uma criança da cidade com id de 1 (por exemplo, New York). Você pode alterar esse número para qualquer outra cidade para devolvê-lo para crianças demasiado
select * from areas where path like '%/1/%'
Outras dicas
Você pode usar
SELECT * FROM Areas WHERE Path LIKE '%/1/%'
Se você tem o caminho armazenado
Se você tem uma profundidade número definido que você sabe que nunca vai ir mais fundo do que isso vai fazer o que quiser:
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: No entanto, se você já tiver o caminho salvo (que eu não notei até agora), o caminho like '% / 1 /%' é claramente a melhor solução.
Em MySQL
:
SELECT *
FROM Areas ap
JOIN Areas ac
ON ac.path > ap.path
AND ac.path < CONCAT(ap.path, ':')
WHERE ap.id = 1
Em PostgreSQL
e Oracle
:
SELECT *
FROM Areas ap
JOIN Areas ac
ON ac.path > ap.path
AND ac.path < ap.path || ':'
WHERE ap.id = 1
Em SQL Server
:
SELECT *
FROM Areas ap
JOIN Areas ac
ON ac.path > ap.path
AND ac.path < ap.path + ':'
WHERE ap.id = 1
LIKE
Ao contrário (sem trocadilhos), esta vai usar um índice em path
.
Procure começar e CONNECT BY no Oracle SQL. Desta forma, você pode selecionar dados com relações hierárquicas (árvore-like).
Tente isto:
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
Eu reutilizar este o tempo todo.
Não sei o que banco de dados que você está usando: Se o SQL Server, use uma expressão de tabela comum ( CTE )
Caso contrário,
Você precisa de algum tipo de código ou procedimento armazenado .. Usando 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
SQLite:
SELECT * FROM Areas where path like
(SELECT path || '%' FROM Areas WHERE area="New York")