我从Postgres表中获得一组有序结果,其中每4行的组代表一组相关数据。我想进一步处理这组结果,以便将每4行的组折叠为具有别名列名的1行,其中每列的值基于该行在组中的位置-我很接近,但是我可以不太正确的查询(我也不相信我正在以最佳方式解决这个问题)。这是场景:
我正在收集调查结果-每个调查都有4个问题,但是每个答案都存储在数据库的单独行中。但是,它们通过提交event_id
相互关联,并且保证结果以固定顺序返回。一组survey_results
如下所示:
event_id | answer
----------------------------
a | 10
a | foo
a | 9
a | bar
b | 2
b | baz
b | 4
b | zip
我想做的就是查询该结果,以便最终输出在自己的行上显示每组4个结果,并带有别名列名。
event_id | score_1 | reason_1 | score_2 | reason_2
----------------------------------------------------------
a | 10 | foo | 9 | bar
b | 2 | baz | 4 | zip
我能得到的最接近的是
SELECT survey_answers.event_id,
(SELECT survey_answers.answer FROM survey_answers FETCH NEXT 1 ROWS ONLY) AS score_1,
(SELECT survey_answers.answer FROM survey_answers OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY) AS reason_1
(SELECT survey_answers.answer FROM survey_answers OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY) AS score_2,
(SELECT survey_answers.answer FROM survey_answers OFFSET 3 ROWS FETCH NEXT 1 ROWS ONLY) AS reason_2
FROM survey_answers
GROUP BY survey_answers.event_id
但是,可以理解的是,这返回正确的行数,但是具有相同的值(event_id
以外):
event_id | score_1 | reason_1 | score_2 | reason_2
----------------------------------------------------------
a | 10 | foo | 9 | bar
b | 10 | foo | 9 | bar
如何构造查询以使其每4行(或更准确地说,在每个唯一OFFSET
组中)应用FETCH
/ event_id
行为?
答案 0 :(得分:2)
首先,这看起来是一个非常糟糕的设计:
没有保证的订单!数据库以随机顺序存储数据,并以随机顺序调用它们。您确实需要一个订单栏。在这种小情况下,这可能会导致意外。
您应该生成两列,一列用于得分,一列用于原因。混合类型不是一个好主意。
不过,对于这个简单而简短的示例,这可能是一个解决方案(请记住,不建议将其用于生产型表):
WITH data AS (
SELECT
*,
row_number() OVER (PARTITION BY event_id) -- 1
FROM
survey_results
)
SELECT
event_id,
MAX(CASE WHEN row_number = 1 THEN answer END) AS score_1, -- 2
MAX(CASE WHEN row_number = 2 THEN answer END) AS reason_1,
MAX(CASE WHEN row_number = 3 THEN answer END) AS score_2,
MAX(CASE WHEN row_number = 4 THEN answer END) AS reason_2
FROM
data
GROUP BY event_id
event_id
添加一个行数。在这种情况下,范围是1到4。这可以用来标识answer
的类型(请参阅小提琴中的中间步骤)。在生产代码中,您应该使用一些订单列来确保订单。然后,窗口函数看起来像PARTITION BY event_id ORDER BY order_column
event_id
和类型ID(row_number)的简单枢纽,它完全符合您的期望答案 1 :(得分:2)
您需要一列来指定顺序。在您的情况下,可能应该是serial
列,并保证每次插入都会增加。我将这样的列称为survey_result_id
。
使用这样的列,您可以执行以下操作:
select event_id,
max(case when seqnum = 1 then answer end) as score_1,
max(case when seqnum = 2 then answer end) as reason_1,
max(case when seqnum = 3 then answer end) as score_2,
max(case when seqnum = 4 then answer end) as reason_2
from (select sr.*,
row_number() over (partition by event_id order by survey_result_id) as seqnum
from survey_results sr
) sr
group by event_id;
如果没有这样的列,则无法可靠地执行所需的操作,因为SQL表表示无序集。