douyao2529 2015-06-23 09:13
浏览 82
已采纳

通过postgresql递归列出所有元素

In my database I have basically a table (entity for Doctrine) called person and it looks like this:

class Person
{
    private $id;

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

I'd like to build a méthod getAllChildren which returns all persons under person1 and recursively all persons under persons who have children.

I'd like to know if I can do this through one recursive SQL request.

UPDATE1

postgres version: 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

I've found http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/, this is pretty much what I need except my model is limitless

  • 写回答

1条回答 默认 最新

  • dongmou3615 2015-06-23 11:12
    关注

    In PostgreSQL you can use a recursive CTE to graciously deal with recursion at table level. For your specific question, the solution would be this (add the other columns from your table as needed; omitted here for brevity and focus):

    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;
    

    The trick here is that you have to work your way up the hierarchy in order to find deeper levels of relationship; the refs column indicates the separation between parent and child. (Should you go down the hierarchy from any given person.id you can not link back up more than 1 level due to the way that the recursive CTE works, AFAIK. You probably can, but probably not as elegantly as in the above solution.)

    I have found that it is oftentimes useful to include self-references, i.e. records where parent = child and refs = 0. The solution then becomes:

      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;
    

    For ease of use, you can wrap the query in a view and then you simply create an entity of the view in Doctrine to get at the data.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)