Postgres 多行作为单行
Postgres Multiple Rows as Single Row
我知道我需要为此使用子查询,但我不确定如何去做。每个列 ID 有多个条目,但我想将它们显示为一行。这是 table 设计:
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 具有绝对值并确定为真或假会使报告更好。该报告将如下所示:
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'
但显然那是行不通的。
使用 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)
因为你只是想检查你是否有给定的 spot
有限列表 - ('left', 'center', 'right')
- 对于每个 position_id
,我看到一个非常简单的解决方案适合你的情况使用 bool_or
aggregation function (see also on SQL Fiddle):
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)
旋转的另一个常见选项是:
但因为只有 true/false,bool_or
在这里似乎绰绰有余。
我知道我需要为此使用子查询,但我不确定如何去做。每个列 ID 有多个条目,但我想将它们显示为一行。这是 table 设计:
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 具有绝对值并确定为真或假会使报告更好。该报告将如下所示:
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'
但显然那是行不通的。
使用 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)
因为你只是想检查你是否有给定的 spot
有限列表 - ('left', 'center', 'right')
- 对于每个 position_id
,我看到一个非常简单的解决方案适合你的情况使用 bool_or
aggregation function (see also on SQL Fiddle):
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)
旋转的另一个常见选项是:
但因为只有 true/false,bool_or
在这里似乎绰绰有余。