Postgres多行作为单行

时间:2016-08-27 17:52:05

标签: postgresql birt

我知道我需要使用子查询,但我不确定如何去做。我每列ID有多个条目,但我想将它们显示为单行。这是表设计:

UUID | position_id | spot
-----+-------------+-----
111  |    1        | left
112  |    1        | right
113  |    3        | center
114  |    4        | right

我想输出这些数据的方式如下:

postion_1_left | position_1_right | postion_3_center | position_4_right
---------------+------------------+------------------+-----------------
     true      |      true        |      true        |      true

这样做的原因是我想将这些数据放入BIRT报告中,并且将每个position_id和spot的绝对值设置为true或false会使报告更好。报告看起来如此:

             left  | center | right
-----------+-------+--------+-----------
position 1 | yes   |  no    |  yes
position 2 | no    |  no    |  no
position 3 | no    |  yes   |  no
position 4 | no    |  no    |  yes

我想不出更好的方法,所以如果有人有建议我会接受它。否则我将继续这个布局,但我很难想出查询。我尝试从这样的查询开始:

SELECT (SELECT spot FROM positions_table WHERE position_id = 3 AND spot = 'left')
from positions_table
WHERE uuid = 'afb36733'

但显然这不起作用。

2 个答案:

答案 0 :(得分:2)

由于您只是希望检查某个有限列表中是否有spot - ('left', 'center', 'right') - 对于每个position_id,我会看到一个非常简单的解决方案,使用{ {3}}(参见bool_or aggregation function):

SELECT
    pt.position_id,
    bool_or(pt.spot = 'left') AS left,
    bool_or(pt.spot = 'right') AS right,
    bool_or(pt.spot = 'center') AS center
FROM
    positions_table pt
GROUP BY
    pt.position_id
ORDER BY
    pt.position_id;

结果:

 position_id | left | right | center 
-------------+------+-------+--------
           1 | t    | t     | f
           3 | f    | f     | t
           4 | f    | t     | f
(3 rows)

然后,您可以使用CASE展开它以更好地格式化(或在表示层中执行此操作):

SELECT
    pt.position_id,
    CASE WHEN bool_or(pt.spot = 'left') THEN 'yes' ELSE 'no' END AS left,
    CASE WHEN bool_or(pt.spot = 'right') THEN 'yes' ELSE 'no' END AS right,
    CASE WHEN bool_or(pt.spot = 'center') THEN 'yes' ELSE 'no' END AS center
FROM
    positions_table pt
GROUP BY
    pt.position_id
ORDER BY
    pt.position_id;

结果:

 position_id | left | right | center 
-------------+------+-------+--------
           1 | yes  | yes   | no
           3 | no   | no    | yes
           4 | no   | yes   | no
(3 rows)

旋转的另一个常见选择是:

但由于它只是真/假,bool_or似乎绰绰有余。

答案 1 :(得分:1)

使用generate_series()填补position_ids中的空白,并将spots汇总到id的数组:

select 
    id, 
    coalesce('left' = any(arr), false) as left,
    coalesce('center' = any(arr), false) as center,
    coalesce('right' = any(arr), false) as right
from (
    select id, array_agg(spot) arr
    from generate_series(1, 4) id
    left join positions_table on id = position_id
    group by 1
    ) s
order by 1;

 id | left | center | right 
----+------+--------+-------
  1 | t    | f      | t
  2 | f    | f      | f
  3 | f    | t      | f
  4 | f    | f      | t
(4 rows)