SQL 查询返回最近的重复项,但不返回非重复项

SQL query is returning most recent duplicates, but not non-duplicates

我有一个 MySQL table (MySQL 5.7),其中包含以下列:id(键)、电子邮件、百分比、file_name。 table 记录学生(通过电子邮件识别)完成某些活动的时间。

我需要 return 一个列表,每个 file_name 学生完成的内容都有一行。如果他们不止一次完成 file_name,我想 return 最近的尝试,基于自动递增的 id。我在这里使用了一些答案来创建以下查询。 file_name 字符串匹配用于隔离特定的 activity 类型和级别:

SELECT id, 
       file_name, 
       percentage
FROM users t1 
WHERE email IN ('name@student.com') 
AND file_name LIKE ('%IL%') 
AND file_name LIKE ('%B2%') 
AND id = (  SELECT MAX(id) 
            FROM users t2 
            WHERE t2.file_name = t1.file_name
         )
GROUP BY file_name, percentage, id
ORDER BY id;

此查询成功 return 任何重复文件名的最新实例,但没有 return 任何非重复文件。所以,如果一个学生完成了 8 file_names 一次,但重复了 1 file_name 两次,这个查询只有 returns 一行,最近的重复。它应该 return 8 个 activity 行,加上最近的副本。

我知道了 运行 here 并且它按预期工作 - return 处理非重复项和最近的重复项,所以我不明白为什么它不是在数据库本身上工作。

我可以使用 CTE 成功执行此操作,但我无法控制数据库,因此无法升级以允许 CTE。

最大的问题是相关子查询正在获取 anyfile_name 的最新 ID email,而不仅仅是与外部查询匹配的电子邮件。此外,外部查询上的 GROUP BY 似乎是不必要的。

保持相同的相关子查询模式,我们可以这样做:

SELECT t1.id
     , t1.email
     , t1.file_name
     , t1.percentage
  FROM users t1 
 WHERE t1.email IN ('name@student.com') 
   AND t1.file_name LIKE ('%IL%') 
   AND t1.file_name LIKE ('%B2%') 
   AND t1.id = ( -- most recent id for (email,file_name) 
                 SELECT MAX(t2.id) 
                   FROM users t2 
                  WHERE t2.email     = t1.email
                    AND t2.file_name = t1.file_name
               )
 ORDER BY t1.id

对于大型集合,相关子查询模式可以吃掉我们的午餐和午餐盒,即使有适当的索引可用,因为对于外部查询处理的每一行(每一行),该子查询将获得 re-executed之前没有被另一个谓词排除)

我倾向于重写查询以避免相关子查询,并测量和比较性能并比较计划(EXPLAIN PLAN 输出。)

我们可以使用内联视图(MySQL 说法中的“派生 table”)获取最新的 id,然后连接回原始 table 以获取与该 id

关联的列
SELECT t1.id
     , t1.email
     , t1.file_name
     , t1.percentage
  -- , t2.*     
 FROM ( -- most recent id for (email,file_name)
        SELECT MAX(t2.id) AS _most_recent_id
             , t2.email
             , t2.file_name
          FROM users t2
         WHERE t2.email IN ('name@student.com')
           AND t2.file_name LIKE ('%IL%') 
           AND t3.file_name LIKE ('%B2%') 
         GROUP
            BY t2.email
             , t2.file_name
      ) t3
 JOIN users t1
   ON t1.id = t3._most_recent_id
ORDER
   BY t1.id

注意:在将内联视图查询(SELECT 别名为 t3)作为派生 table 合并到外部 [=44] 之前,我们可以对其进行测试和工作=].

在此示例中,t3(内联视图查询)到 return 列 t2.emailt2.file_name 并不是绝对必要的。但它确实让验证结果变得更容易,我们得到了给定电子邮件的最高 ID 和 file_name。 (我们可以在另一个更简单的语句 SELECT * FROM users WHERE email = ? AND file_name = ? 中使用 returned 值来获取我们从中选择最大 ID 的整组行。