[英]SQL/Postgres - collapse every N rows into 1 based on row position in group
我从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行批处理(或更准确地说,在event_id
的每个唯一集合中)应用OFFSET
/ FETCH
行为?
首先,这看起来是一个非常糟糕的设计:
没有保证的订单! 数据库以随机顺序存储数据,并以随机顺序调用它们。 您确实需要一个订单栏。 在这种小情况下,这可能会导致意外。
您应该生成两列,一列得分,一列原因。 混合类型不是一个好主意。
不过,对于这个简单而简短的示例,这可能是一个解决方案(请记住,不建议在生产性表中使用此方法):
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)的简单枢轴,它确实可以实现您的期望 您需要一列来指定顺序。 在您的情况下,它可能应该是一个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表表示无序集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.