如何使用distinct分隔层次结构值

时间:2013-09-30 06:35:14

标签: php postgresql

我有一个包含(srno, Name, Product, Amount).列的表格 值是

(1,    Ronak, Iphone,  40000),
                (2,    Ronak, Iphone,  36000),
                (3,    Ronak, Iphone,  38000),
                (4,    Naman, Iphone,  40000),
                (5,    Naman, Ipad,    20000),
                (6,    Nihar, Ipad,    20000),
                (7,    Ronak, Ipad,    19000),
                (8,    Naman, Iphone,  37000),
                (9,    Nihar, Ipad,    40000),

我想获取不同的值并将其存储在具有各自parent_id的另一个表中。输出应如下所示:

(uid, name, parent_id)
(1,  Ronak,   NULL),
(2,  Naman,   NULL),
(3,  Nihar,   NULL),
(4,  Iphone,  1),
(5,  Iphone,  2),
(6,  Ipad,    2),
(7,  Ipad,    3),
(8,  Ipad,    1),
(9,  40000,   4),
(10, 36000,   4),
(11, 38000,   4),
(12, 40000,   5),
(13, 20000,   6),
(14, 20000,   7),
(15, 19000,   8),
(16, 37000,   5),
(17, 40000,   7),

parent_id是同一张表中的uid

谁能告诉我postgresql中的哪些查询可以实现所需的输出。我正在使用PHP和PostgreSQL。

2 个答案:

答案 0 :(得分:1)

这可以完成工作,但每个添加的列需要一步。我不认为它可以用递归CTE(可能有辅助阵列)来完成。 BTW:奇怪的存储层次结构!

CREATE TABLE oldstuff
        ( num INTEGER NOT NULL PRIMARY KEY
        , name varchar NOT NULL
        , thing varchar NOT NULL
        , figure INTEGER NOT NULL
        , UNIQUE (name,thing,figure)
        );

INSERT INTO oldstuff(num,name,thing,figure) VALUES
(1, 'Ronak', 'Iphone',  40000),
(2, 'Ronak', 'Iphone',  36000),
(3, 'Ronak', 'Iphone',  38000),
(4, 'Naman', 'Iphone',  40000),
(5, 'Naman', 'Ipad',    20000),
(6, 'Nihar', 'Ipad',    20000),
(7, 'Ronak', 'Ipad',    19000),
(8, 'Naman', 'Iphone',  37000),
(9, 'Nihar', 'Ipad',    40000);

CREATE TABLE newstuff
        ( num SERIAL NOT NULL PRIMARY KEY
        , thing varchar NOT NULL
        , parent_num INTEGER REFERENCES newstuff(num)
        , UNIQUE (thing,parent_num)
        );

INSERT INTO newstuff(thing)
SELECT DISTINCT os.name
FROM oldstuff os
GROUP BY os.name
        ;

INSERT INTO newstuff(thing,parent_num)
SELECT DISTINCT os.thing, ns.num
FROM oldstuff os
LEFT JOIN newstuff ns ON ns.thing= os.name
GROUP BY os.thing, ns.num
        ;

INSERT INTO newstuff(thing,parent_num)
SELECT os.figure::varchar, COALESCE(n1.num,n0.num)
FROM oldstuff os
JOIN newstuff n0 ON n0.thing= os.name AND n0.parent_num IS NULL
JOIN newstuff n1 ON n1.thing= os.thing AND n1.parent_num =n0.num
        ;

SELECT * FROM newstuff ;

结果:

   num | thing  | parent_num 
-----+--------+------------
   1 | Naman  |           
   2 | Ronak  |           
   3 | Nihar  |           
   4 | Ipad   |          1
   5 | Ipad   |          2
   6 | Ipad   |          3
   7 | Iphone |          1
   8 | Iphone |          2
   9 | 20000  |          4
  10 | 37000  |          7
  11 | 40000  |          7
  12 | 19000  |          5
  13 | 36000  |          8
  14 | 38000  |          8
  15 | 40000  |          8
  16 | 20000  |          6
  17 | 40000  |          6

答案 1 :(得分:0)

可以通过连接更容易完成,但我认为最有效的方法是使用窗口函数:

with cte as (
    select
        t.Name, t.Product, t.Amount,
        dense_rank() over(order by t.Name) as Name_ID,
        dense_rank() over(order by t.Product, t.Name) as Product_ID,
        dense_rank() over(order by t.Product, t.Name, t.Amount) as Amount_ID
    from Table1 as t
), cte2 as (
    select
        Name, Product, Amount,
        Name_ID,
        max(Name_ID) over() + Product_ID as Product_ID,
        max(Name_ID) over() + max(Product_ID) over() + Amount_ID as Amount_ID
    from cte
)
select distinct
    Name_ID as uid, Name as name, null::int as parent_id
from cte2

union all

select distinct
    Product_ID as uid, Product as name, Name_ID as parent_id
from cte2

union all

select distinct
    Amount_ID as uid, Amount::varchar(10) as name, Product_ID as parent_id
from cte2
order by uid, parent_id

<强> sql fiddle demo