如何在postgresql中转置这个表

时间:2014-03-13 11:32:31

标签: database postgresql crosstab transpose

我有这张桌子:

 lnumber |    lname       |           bez_gem              
---------+----------------+------------------------------
       1 | name1          | Berg b.Neumarkt i.d.OPf.
       1 | name1          | Altdorf b.Nürnberg
       2 | name2          | Berg b.Neumarkt i.d.OPf.
       2 | name2          | Altdorf b.Nürnberg
       3 | name3          | Mainleus
       3 | name3          | Weismain
       4 | name4          | Weismain
       4 | name4          | Mainleus

查询的代码是:

WITH double AS (
SELECT
    partnumber,
    bez_gem
FROM accumulation a, municipality b
    WHERE ST_Intersects(a.geom, b.geom)
        AND EXISTS (
             SELECT 
                lnumber 
            FROM mun_more_than_once c 
                WHERE a.partnumber=c.lnumber)
        ORDER BY partnumber)

SELECT
    landslide.lnumber,
    lname,
    bez_gem
FROM double, landslide
    WHERE double.partnumber=landslide.lnumber
        ORDER BY lnumber

我想以这种格式进行转置

 lnumber |    lname       |           bez_gem1        |  bez_gem2   
---------+----------------+------------------------------------------------
       1 | name1          | Berg b.Neumarkt i.d.OPf.  | Altdorf b.Nürnberg
       2 | name2          | Berg b.Neumarkt i.d.OPf.  | Altdorf b.Nürnberg

2 个答案:

答案 0 :(得分:1)

这取决于。如果每bez_gem总共有两个lnumber,则可以使用:

SELECT lnumber, lname
     , min(bez_gem) AS bez_gem1
     , max(bez_gem) AS bez_gem2
FROM   test
GROUP  BY 1,2
ORDER  BY 1;

SQL Fiddle.

请注意,您的问题中未定义同伴的顺序。整理规则(字母顺序)在我的例子中决定。

对于实际交叉制表,您可以使用附加模块tablefunc中的crosstab()功能。但是您的表缺少类别名称(没有指示哪一行包含bez_gem1以及哪个bez_gem2)。说明,细节和链接:
PostgreSQL Crosstab Query

答案 1 :(得分:0)

SQLFiddle

数据

-- drop table if exists test;

create table test (lnumber int, lname varchar, bez_gem varchar);

    insert into test values

           (1 , 'name1'          , 'Berg b.Neumarkt i.d.OPf.'),
           (1 , 'name1'          , 'Altdorf b.Nürnberg'),
           (2 , 'name2'          , 'Berg b.Neumarkt i.d.OPf.'),
           (2 , 'name2'          , 'Altdorf b.Nürnberg'),
           (3 , 'name3'          , 'Mainleus'),
           (3 , 'name3'          , 'Weismain'),
           (4 , 'name4'          , 'Weismain'),
           (4 , 'name4'          , 'Mainleus'),
           (4 , 'name4'          , 'XXMainleus')       
           ;

查询

select
  lnumber,
  lname,
  max(case when rn = 1 then bez_gem end) as bez_gem1,
  max(case when rn = 2 then bez_gem end) as bez_gem2,
  max(case when rn = 3 then bez_gem end) as bez_gem3   
from
  (
  select
    *,
    row_number() over(partition by lname) rn
  from
    test
  ) a
 group by
  lnumber,
  lname

结果

1;name1;Berg b.Neumarkt i.d.OPf.;Altdorf b.Nürnberg;
2;name2;Berg b.Neumarkt i.d.OPf.;Altdorf b.Nürnberg;
3;name3;Mainleus;Weismain;
4;name4;Weismain;Mainleus;XXMainleus

旧答案

如果每个lnumber只有两个可能的行(您应该将这些重要信息添加到您的问题中),您只需使用minmax

WITH double AS (
SELECT
    partnumber,
    bez_gem
FROM accumulation a, municipality b
    WHERE ST_Intersects(a.geom, b.geom)
        AND EXISTS (
             SELECT 
                lnumber 
            FROM mun_more_than_once c 
                WHERE a.partnumber=c.lnumber)
        ORDER BY partnumber)

SELECT
    landslide.lnumber,
    lname,
    min(bez_gem) as bez_gem1,
    max(bez_gem) as bez_gem2
FROM double, landslide
    WHERE double.partnumber=landslide.lnumber
group by
    landslide.lnumber,
    lname
ORDER BY lnumber

如果每个lnumber可能有两行以上,并且您确实需要交叉表,那么在SO(example)上的PostgreSQL中有很多关于交叉表的问题。作为替代方案,您可以尝试以下方法。

由于这是一次性分析,因此您可以轻松获得最大数量的唯一bez_gem值:

select 
  landslide.lnumber, 
  count(distinct bez_gem) cnt 
from 
  <<some_data>> 
group by 
  landslide.lnumber 
order by 
   cnt desc limit 1

然后你可以使用:

select
 landslide.lnumber,
 lname,
 max(case when rn=1 then bez_gem end) as bez_gem1,
 max(case when rn=2 then bez_gem end) as bez_gem2,
 max(case when rn=3 then bez_gem end) as bez_gem3,
 max(case when rn=4 then bez_gem end) as bez_gem4,
 max(case when rn=5 then bez_gem end) as bez_gem5,
 ... up to cnt ...
from(
  select
   landslide.lnumber,
   lname,
   bez_gem,
   row_number() over(partition by landslide.lnumber) rn
  from
   <<some_data>>
 ) a
group by
  landslide.lnumber,
  lname

对于您的数据和5个可能的值,它们看起来像:

WITH double AS (
SELECT
    partnumber, bez_gem
FROM 
  accumulation a, municipality b
WHERE 
  ST_Intersects(a.geom, b.geom)
  AND EXISTS (
              SELECT lnumber 
              FROM mun_more_than_once c 
              WHERE a.partnumber=c.lnumber)
ORDER BY 
  partnumber
)

select
  landslide.lnumber,
  lname,
  max(case when rn=1 then bez_gem end) as bez_gem1,
  max(case when rn=2 then bez_gem end) as bez_gem2,
  max(case when rn=3 then bez_gem end) as bez_gem3,
  max(case when rn=4 then bez_gem end) as bez_gem4,
  max(case when rn=5 then bez_gem end) as bez_gem5
from (
  select
      landslide.lnumber,
      lname,
      bez_gem,
      row_number() over(partition by landslide.lnumber) rn
  from 
      double, landslide
  where 
    double.partnumber=landslide.lnumber
) a       
group by
  landslide.lnumber,
  lname