簡體   English   中英

SQL / Postgres-根據組中的行位置將每N行折疊為1

[英]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行為?

演示:db <> fiddle

首先,這看起來是一個非常糟糕的設計:

  1. 沒有保證的訂單! 數據庫以隨機順序存儲數據,並以隨機順序調用它們。 您確實需要一個訂單欄。 在這種小情況下,這可能會導致意外。

  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
  1. row_number() 窗口函數為每個event_id添加行數。 在這種情況下,范圍是1到4。這可以用來識別answer的類型(請參閱小提琴中的中間步驟)。 在生產代碼中,您應該使用一些訂單列來確保訂單。 然后,窗口函數將看起來像PARTITION BY event_id ORDER BY order_column
  2. 這是關於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM