我有表名m_option
:獲得2個選項爲每個每個student_id數據最小值
m_option_id m_student_id value 1 1 5 2 1 5 3 1 6 4 1 7 5 2 1 6 2 2 7 2 3 8 2 3 9 2 4
我想要得到的2行與分value
每個m_student_id
:
m_option_id m_student_id value 1 1 5 2 1 5 5 2 1 6 2 2
我有表名m_option
:獲得2個選項爲每個每個student_id數據最小值
m_option_id m_student_id value 1 1 5 2 1 5 3 1 6 4 1 7 5 2 1 6 2 2 7 2 3 8 2 3 9 2 4
我想要得到的2行與分value
每個m_student_id
:
m_option_id m_student_id value 1 1 5 2 1 5 5 2 1 6 2 2
您可以使用row_number
窗口函數:
SELECT m_option_id, m_student_id, value
FROM (
SELECT
m_option_id, m_student_id, value,
row_number() OVER (PARTITION BY m_student_id ORDER BY value)
FROM m_option
) t
WHERE
row_number <= 2;
row_number
將計算其組內每行的數量。然後,我們使用該數字來過濾每個組的前2行(即最低value
)。
或者,你可以使用子查詢LATERAL
:
SELECT m_option_id, m_student_id, value
FROM (SELECT DISTINCT m_student_id FROM m_option) s,
LATERAL (
SELECT m_option_id, value
FROM m_option
WHERE s.m_student_id=m_student_id
ORDER BY value
LIMIT 2
) t;
這將經歷的m_student_id
所有不同的值,併爲他們每個人都會使用子查詢LATERAL
找到前2行。
假設有可能每個學生很多行表m_option
,性能的關鍵是使用索引。如果你有一個獨立student
表列出所有學生的唯一(你通常會有),這是最有效的。然後:
SELECT m.m_option_id, s.student_id AS m_student_id, m.value
FROM student s
, LATERAL (
SELECT m_option_id, value
FROM m_option
WHERE m_student_id = s.student_id -- PK of table student
ORDER BY value
LIMIT 2
) m;
一個多列索引上m_option
使這個快速:
CREATE INDEX m_option_combo_idx ON m_option (m_student_id, value);
如果你能得到index-only scans出來的,追加列m_option_id
的最後一個索引項:
CREATE INDEX m_option_combo_idx ON m_option (m_student_id, value, m_option_id)
按此順序的索引列。
蒸餾的student_id
從m_option
唯一列表會招致昂貴的順序掃描過m_option
並使任何性能優勢。
這排除沒有任何相關行的學生m_option
。使用LEFT JOIN LATERAL() ON true
包括這些學生的結果(擴展了NULL
值失蹤的選項):
如果你沒有一個student
表中,其他快速選擇是遞歸的CTE 。
詳細的變種兩種解釋:
感謝。沒關係 – duyanhphamkiller