Question

I have this table:

 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

The code for the query is:

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

I want to transpose in this format

 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
Was it helpful?

Solution 2

SQLFiddle

Data

-- 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')       
           ;

Query

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

Result

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

Old Answer

If you have only two possible rows for every lnumber (you should add this important info to your question), you can simply use min and max:

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

If you have possibly more than two rows for every lnumber and you really need crosstab, there is a lot of questions regarding crosstab in PostgreSQL on SO (example). As an alternative you can try the following approach.

Because this is one-time analysis, you can easily get maximum number of unique bez_gem values:

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

Then you can use:

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

For your data and 5 possible values it would look like:

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

OTHER TIPS

It depends. If you always have two bez_gem per lnumber, you can simply use:

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.

Note that the order of peers is undefined in your question. Collation rules (alphabetical order) decide in my example.

For an actual cross tabulation you would use the crosstab() function from the additional module tablefunc. But your table is missing a category name (no indication which row holds bez_gem1 and which bez_gem2). Explanation, details and links:
PostgreSQL Crosstab Query

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top