我有表名m_option
:
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
我想为每个value
获得最少m_student_id
的2行:
m_option_id m_student_id value 1 1 5 2 1 5 5 2 1 6 2 2
答案 0 :(得分:1)
您可以使用<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
窗口功能:
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;
将计算其组中每行的数量。然后我们使用该数字来过滤每组中的前2行(即最低row_number
)。
或者,您可以使用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
子查询找到前2行。
答案 1 :(得分:1)
假设表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
两种变体的详细解释: