SQL:如何获取在同一个表中维护的数据的父记录和子记录

时间:2017-12-13 11:04:03

标签: sql postgresql

这就是我的表(locationgroup)的样子。父/子关系正在同一个表中维护,并且可能有更多记录(ID可能不是按顺序)

+------+------------+------------+--------------+---------------+-----------+
|   id | name       |   parentid |   customerid | type          | deleted   |
|------+------------+------------+--------------+---------------+-----------|
|  131 | Zone       |          0 |           79 | zone          | False     |
|  132 | State      |        131 |           79 | state         | False     |
|  136 | Center 3   |        133 |           79 | servicecentre | False     |
|  134 | Center 1   |        133 |           79 | servicecentre | False     |
|  135 | Center 2   |        133 |           79 | servicecentre | False     |
|  133 | City       |        132 |           79 | city          | False     |
|  137 | Center 4   |        133 |           79 | servicecentre | False     |
+------+------------+------------+--------------+---------------+-----------+

我想要达到的目标是获得任何给定身份的父母和孩子。

例如:对于id - 131,结果应为

+------+------------+------------+--------------+---------------+-----------+
|   id | name       |   parentid |   customerid | type          | deleted   |
|------+------------+------------+--------------+---------------+-----------|
|  131 | Zone       |          0 |           79 | zone          | False     |
|  132 | State      |        131 |           79 | state         | False     |
|  133 | City       |        132 |           79 | city          | False     |
|  134 | Center 1   |        133 |           79 | servicecentre | False     |
|  135 | Center 2   |        133 |           79 | servicecentre | False     |
|  136 | Center 3   |        133 |           79 | servicecentre | False     |
|  137 | Center 4   |        133 |           79 | servicecentre | False     |
+------+------------+------------+--------------+---------------+-----------+

因此,对于id - 137,结果应为

+------+------------+------------+--------------+---------------+-----------+
|   id | name       |   parentid |   customerid | type          | deleted   |
|------+------------+------------+--------------+---------------+-----------|
|  131 | Zone       |          0 |           79 | zone          | False     |
|  132 | State      |        131 |           79 | state         | False     |
|  133 | City       |        132 |           79 | city          | False     |
|  137 | Center 4   |        133 |           79 | servicecentre | False     |
+------+------------+------------+--------------+---------------+-----------+

我只能通过查询获得子记录

WITH RECURSIVE locgrp AS (
        SELECT
        lg.*
        FROM locationgroup lg
        WHERE lg.customerid = 79 AND lg.id IN (133) AND lg.deleted = FALSE
        UNION
        SELECT
        lg_union_1.*
        FROM locationgroup lg_union_1
        INNER JOIN locgrp lg_union_2 ON lg_union_1.parentid = lg_union_2.id
        WHERE lg_union_1.deleted = FALSE AND lg_union_2.deleted = FALSE
        )
        SELECT *
        FROM locgrp ORDER BY id ASC;

例如:对于id - 137,我得到的是

+------+------------+------------+--------------+---------------+-----------+
|   id | name       |   parentid |   customerid | type          | deleted   |
|------+------------+------------+--------------+---------------+-----------|
|  137 | Center 4   |        133 |           79 | servicecentre | False     |
+------+------------+------------+--------------+---------------+-----------+

我可以通过改变行

来达到预期的效果

INNER JOIN locgrp lg_union_2 ON lg_union_1.parentid = lg_union_2.id

在查询中

INNER JOIN locgrp lg_union_2 ON lg_union_1.id = lg_union_2.parentid

但是他们出于同样的目的而进行了两次不同的查询。

如何修改我的查询以获取具有相同查询的父记录和子记录。我应该坚持使用递归查询或其他任何东西。

1 个答案:

答案 0 :(得分:0)

因为你对一个功能很好,所以这样的事情应该有效。我并不假装这是最酷的东西,但我相信它会产生正确的结果:

CREATE OR REPLACE FUNCTION recurse_me(cust_id integer, loc_id integer)
  RETURNS SETOF locationgroup AS
$BODY$
declare
  rw locationgroup%rowtype;
begin

  FOR rw IN
    WITH RECURSIVE locgrp AS (
      SELECT
      lg.*
      FROM locationgroup lg
      WHERE lg.customerid = cust_id AND lg.id = loc_id AND lg.deleted = FALSE
      UNION
      SELECT
      lg_union_1.*
      FROM locationgroup lg_union_1
      INNER JOIN locgrp lg_union_2 ON lg_union_1.parentid = lg_union_2.id
      WHERE lg_union_1.deleted = FALSE AND lg_union_2.deleted = FALSE
    )
    SELECT * FROM locgrp
  LOOP
    return next rw;
  END LOOP;

  FOR rw IN
    WITH RECURSIVE locgrp AS (
      SELECT
      lg.*
      FROM locationgroup lg
      WHERE lg.customerid = cust_id AND lg.id = loc_id AND lg.deleted = FALSE
      UNION
      SELECT
      lg_union_1.*
      FROM locationgroup lg_union_1
      INNER JOIN locgrp lg_union_2 ON lg_union_1.id = lg_union_2.parentid
      WHERE lg_union_1.deleted = FALSE AND lg_union_2.deleted = FALSE
    )
    SELECT * FROM locgrp where id != loc_id
  LOOP
    return next rw;
  END LOOP;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  ROWS 1000;

实现:

postgres=# select * from recurse_me (79, 133) order by id;
 id  |     name     | parentid | customerid |      type       | deleted
-----+--------------+----------+------------+-----------------+---------
 131 |  Zone        |        0 |         79 |  zone           | f
 132 |  State       |      131 |         79 |  state          | f
 133 |  City        |      132 |         79 |  city           | f
 134 |  Center 1    |      133 |         79 |  servicecentre  | f
 135 |  Center 2    |      133 |         79 |  servicecentre  | f
 136 |  Center 3    |      133 |         79 |  servicecentre  | f
 137 |  Center 4    |      133 |         79 |  servicecentre  | f
(7 rows)

postgres=# select * from recurse_me (79, 137) order by id;
 id  |     name     | parentid | customerid |      type       | deleted
-----+--------------+----------+------------+-----------------+---------
 131 |  Zone        |        0 |         79 |  zone           | f
 132 |  State       |      131 |         79 |  state          | f
 133 |  City        |      132 |         79 |  city           | f
 137 |  Center 4    |      133 |         79 |  servicecentre  | f
(4 rows)