[英]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.