如何获取每个学生一个月内最新的参赛作品

问题描述 投票:0回答:3

我正在尝试获取每个月特定学生健康检查的类别。然而,有时一个月会有多个条目。如何使用 SQL 获取当月的最新条目?

以下是我正在使用的SQL:

SELECT  mt_tagged_student.student_id, 
        mt_inspection.category,
        mt_inspection.created_date as entry_date
FROM public.mt_tagged_student
        LEFT JOIN public.mt_student  On mt_tagged_student.student_id = mt_student.id
        LEFT JOIN public.mt_inspection  On mt_inspection.student_id = mt_student.id
where mt_inspection.created_date between '2023-10-1 00:00:01' AND '2023-10-31 23:59:59'
    and mt_inspection.category = 1
ORDER BY mt_tagged_student.student_id ASC, entry_date Desc

这是 SQL 的一些结果,

突出显示的部分显示有时一个月内有两次条目。如何只获取该月的最新条目?

sql postgresql greatest-n-per-group
3个回答
1
投票

DISTINCT ON
的教科书示例:

SELECT DISTINCT ON (s.student_id)
       s.student_id
     , i.category
     , i.created_date AS entry_date
FROM   public.mt_tagged_student  t
JOIN   public.mt_student    s USING (student_id)
JOIN   public.mt_inspection i USING (student_id)
WHERE  i.created_date >= '2023-10-1'
AND    i.created_date <  '2023-11-1'
AND    i.category = 1
ORDER  BY s.student_id, i.created_date DESC NULLS LAST;

也应该像您指出的那样,每月最多只执行几个条目。参见:

另外,不要将

BETWEEN
与时间戳一起使用

我将

LEFT [OUTER] JOIN
的两个实例都转换为普通
[INNER] JOIN
,因为前者与右表中的
WHERE
条件结合起来没有任何意义。参见:

我一开始就加入了

DESC NULLS LAST
,因为
LEFT JOIN
可以引入空值。现在已删除,但我们仍然不知道
created_date
本身是否已定义
NOT NULL
。参见:


0
投票

您可以按如下方式使用

NOT EXISTS

SELECT  mt_tagged_student.student_id, 
        mi.category,
        mi.created_date as entry_date
FROM public.mt_tagged_student
        LEFT JOIN public.mt_student  On mt_tagged_student.student_id = mt_student.id
        LEFT JOIN public.mt_inspection mi On mi.student_id = mt_student.id
where mi.created_date between '2023-10-1 00:00:01' AND '2023-10-31 23:59:59'
    and mi.category = 1
    and not exists (select 1 from public.mt_inspection mi 
                   where mi.student_id = mii.student_id
                   and date_trunc('month', mi.created_date) = date_trunc('month', mii.created_date)
                   and mii.created_date > mi.created_date
                   and mii.category = 1)
ORDER BY mt_tagged_student.student_id ASC, entry_date Desc  

或者您可以使用

ROW_NUMBER
,如下所示:

select t.student_id, t.category, t.entry_date from
(SELECT      mt_tagged_student.student_id, 
            mt_inspection.category,
            mt_inspection.created_date as entry_date,
            row_number() over (partition by mt_tagged_student.student_id, date_trunc('month', mt_inspection.created_date) order by mt_inspection.created_date desc) as rn
    FROM public.mt_tagged_student
            LEFT JOIN public.mt_student  On mt_tagged_student.student_id = mt_student.id
            LEFT JOIN public.mt_inspection  On mt_inspection.student_id = mt_student.id
    where mt_inspection.created_date between '2023-10-1 00:00:01' AND '2023-10-31 23:59:59'
        and mt_inspection.category = 1) t
    ORDER BY t.student_id ASC, t.entry_date Desc;

0
投票
WITH ranked_inspection AS (
    SELECT
        mt_tagged_student.student_id,
        mt_inspection.category,
        mt_inspection.created_date AS entry_date,
        ROW_NUMBER() OVER (PARTITION BY mt_tagged_student.student_id
                           ORDER BY mt_inspection.created_date DESC) AS rnk
    FROM
        public.mt_tagged_student
        LEFT JOIN public.mt_student ON mt_tagged_student.student_id = mt_student.id
        LEFT JOIN public.mt_inspection ON mt_inspection.student_id = mt_student.id
    WHERE
        mt_inspection.created_date >= '2023-10-1'
        AND mt_inspection.created_date <  '2023-11-1'
        AND mt_inspection.category = 1
)
SELECT
    student_id,
    category,
    entry_date
FROM
    ranked_inspection
WHERE
    rnk = 1
ORDER BY
    student_id ASC, entry_date DESC;
© www.soinside.com 2019 - 2024. All rights reserved.