按对象排序关系(PostgreSQL)

时间:2012-04-18 21:44:20

标签: postgresql

例如有2个表:

第一名:对象&父列

object | parent 
-------+---------
object1| null       
object2| object1  
object3| null  

第二名:对象&参考专栏

object | reference
-------+---------
object1| null       
object2| null       
object3| object1       

需要按以下顺序查询表:父是第一个,然后是 - 子(s),具有父对象引用的对象。

object1
object2
object3

是否可以在一个SQL查询中执行或需要在数组中手动​​排序?似乎这是一项经典任务,可能解决方案已存在于某个地方?

4 个答案:

答案 0 :(得分:1)

这是你要找的吗?

CREATE TABLE oparen (object varchar(10), parent varchar(10));
CREATE TABLE oref (object varchar(10), ref varchar(10));
INSERT INTO oparen VALUES
    ('object1',null),('object2','object1'),
    ('object3',null),('object4','object2');
INSERT INTO oref VALUES
    ('object1',null),('object2',null),('object3','object1'),
    ('object5','object6'),('object6','object1'),('object7','object4');

WITH hier AS (
    SELECT parent AS obj, 1 AS rank FROM oparen
     WHERE parent IS NOT NULL
    UNION
    SELECT object, 2 FROM oparen
     WHERE parent IS NOT NULL
    UNION
    SELECT object, 3 FROM oref
     WHERE ref IS NOT NULL),
allobj AS (
    SELECT object AS obj FROM oparen
    UNION
    SELECT object FROM oref)
SELECT a.obj, coalesce(h.rank, 4) AS rank
  FROM allobj a LEFT JOIN hier h ON a.obj = h.obj
 ORDER BY coalesce(h.rank, 4), a.obj;

编辑:在以下答案中的改进示例之后,以下查询应该可以解决问题:

WITH parents AS (
    SELECT parent AS obj, 1 AS rank FROM oparen
     WHERE parent IS NOT NULL
    ),
family AS (
    SELECT * FROM parents
    UNION ALL
    SELECT object, 2 FROM oparen op
     WHERE parent IS NOT NULL
       AND NOT EXISTS (SELECT obj FROM parents WHERE obj = op.object)
    ),
hier AS (
    SELECT * FROM family
    UNION ALL
    SELECT object AS obj, coalesce(f.rank + 2, 5) AS rank
      FROM oref LEFT JOIN family f ON oref.ref = f.obj
     WHERE ref IS NOT NULL
    ),
allobj AS (
    SELECT object AS obj FROM oparen
    UNION
    SELECT object FROM oref)
SELECT a.obj, h.rank AS rank
  FROM allobj a LEFT JOIN hier h ON a.obj = h.obj
 ORDER BY h.rank, a.obj;

根据新要求更新顶部的测试平台创建。

答案 1 :(得分:0)

我插入了以下数据:

INSERT INTO oparen VALUES
    ('object1',null),('object2','object1'),('object3',null),('object4','object2');
INSERT INTO oref VALUES
    ('object1',null),('object2',null),('object3','object1'),('object5','object6'),('object6','object1');

订单不正确,object2列出两次。关于obj的DISTINCT也打破了顺序。应该去6然后5。

答案 2 :(得分:0)

不,不起作用:检查其他数据并简化使用,并且只能通过oref表内容:

INSERT INTO oref VALUES
('object1',null),('object2',null),('object3','object1'),
('object5','object6'),('object6','object1'),('object7','object4'), ('object4','object5');

WITH family AS (
    SELECT object AS obj, 1 AS rank FROM oref
     WHERE ref IS NULL
    ),
hier AS (
    SELECT * FROM family
    UNION ALL
    SELECT object AS obj, coalesce(f.rank + 2, 5) AS rank
      FROM oref LEFT JOIN family f ON oref.ref = f.obj
     WHERE ref IS NOT NULL
    ),
allobj AS (
    SELECT object AS obj FROM oref)
SELECT a.obj, h.rank AS rank
  FROM allobj a
  LEFT JOIN hier h ON a.obj = h.obj
 ORDER BY h.rank, a.obj;

认为需要在这里使用递归查询。将在这里写和发表。

答案 3 :(得分:0)

以下递归查询有效:

WITH RECURSIVE tables(object, rank) AS (
    SELECT DISTINCT o.object, 1 AS rank FROM oref o
    WHERE o.ref IS NULL
    UNION
    SELECT o.object, t.rank + 1 AS rank
    FROM (SELECT DISTINCT o.object, o.ref FROM oref o
            WHERE ref IS NOT NULL) o, tables t
    WHERE o.ref = t.object AND rank <= t.rank
),
ordered AS (
    SELECT * FROM tables
)
SELECT * FROM tables 
WHERE tables.rank = (SELECT MAX(rank) FROM ordered WHERE ordered.object = tables.object)
ORDER BY rank;

任何评论,问题,异议,主张? ;)