2015-06-23 5 views
1

В моей базе данных у меня в основном таблица (объект для Doctrine) называется человек, и это выглядит следующим образом:Список всех элементов рекурсивно через PostgreSQL

class Person 
{ 
    private $id; 

    /** 
    * @ORM\ManyToOne(targetEntity="Person") 
    */ 
    private $parent; 
} 

Я хотел бы построить МЕТОД getAllChildren, который возвращает все лица до person1 и рекурсивно все лица под лицами, у которых есть дети.

Я хотел бы знать, могу ли я сделать это через один рекурсивный запрос SQL.

Update1

Postgres версия: 9,1

-- Table: person 

    -- DROP TABLE person; 

    CREATE TABLE person 
    (
     id serial NOT NULL, 
     parent_id integer, 
     nom character varying(255) DEFAULT NULL::character varying, 
     prenom character varying(255) DEFAULT NULL::character varying, 
     age integer, 
     description text, 
     statut character varying(255) DEFAULT NULL::character varying, 
     CONSTRAINT person_pkey PRIMARY KEY (id), 
     CONSTRAINT fk_7cbkzkd63HRzVK8e FOREIGN KEY (parent_id) 
     REFERENCES person(id) MATCH SIMPLE 
) 

UPDATE2

Я нашел http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/, это довольно много, что мне нужно кроме моя модель безгранична

+1

Да, вы можете. Но если вы хотите получить ответ SQL, укажите данные SQL: определение таблицы, по крайней мере, и, желательно, некоторые образцы данных и версию PG. – Patrick

+0

@Patrick, пожалуйста, ознакомьтесь с моим обновленным сообщением – smarber

+0

Ваш DDL является неполным: 'CONSTRAINT fk_7cbkzkd63HRzVK8e FOREIGN KEY (parent_id) ССЫЛКИ person (id)' – joop

ответ

2

В PostgreSQL вы можете использовать recursive CTE, чтобы любезно разрешить рекурсию на уровне таблицы. Для вашего конкретного вопроса, то решение было бы это (добавить другие столбцы из таблицы в случае необходимости, здесь опущены для краткости и фокус):

WITH RECURSIVE p(parent, child, refs) AS (
    SELECT parent_id, id, 1 FROM person WHERE parent_id IS NOT NULL 
UNION 
    SELECT parent_id, child, refs+1 
    FROM person JOIN p ON id = parent) 
SELECT * FROM p WHERE parent IS NOT NULL 
ORDER BY parent, child; 

Хитрость здесь в том, что вы должны работать ваш путь до иерархию, чтобы найти более глубокие уровни отношений; колонка refs указывает на разделение между parent и child. (Если вы идете вниз иерархии от любого заданного person.id, вы не можете связать резервную копию более 1 уровня из-за того, что рекурсивный CTE работает, AFAIK. Возможно, вы, возможно, не так изящны, как в приведенном выше решении.)

Я обнаружил, что часто полезно включать самореференции, то есть записи, где parent = child и refs = 0. Решение становится:

WITH RECURSIVE p(parent, child, refs) AS (
    SELECT id, id, 0 FROM person WHERE parent_id IS NOT NULL -- the self-reference 
    UNION 
    SELECT parent_id, child, refs+1 
    FROM person JOIN p ON id = parent) 
    SELECT * FROM p WHERE parent IS NOT NULL 
UNION 
    SELECT id AS parent, id AS child, 0 AS refs -- add the top-level node 
    FROM person 
    WHERE parent_id IS NULL 
ORDER BY parent, child; 

Для простоты использования, вы можете обернуть запрос в представлении, а затем вы просто создать объект из вида в Доктрине, чтобы получить на данные.

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