【问题标题】:Join on rows that have maximum value in Access 2016加入 Access 2016 中具有最大值的行
【发布时间】:2019-04-18 15:43:01
【问题描述】:

尝试在 Access 2016 中选择所有学生,并为每个学生加入一个计划。它工作正常,但它不是选择的最新计划...... 如果我只为特定的 student_id 运行子查询,它正在工作并且选择了最近的计划。

SELECT dbo_Student.*, a.*
FROM dbo_Student LEFT JOIN (SELECT TOP 1 * FROM dbo_Plan ORDER BY Year 
DESC, Version DESC)  AS a ON dbo_Student.ID = a.student_id
WHERE Archived = FALSE
ORDER BY Name;

编辑
多亏了 C perkins,这是迄今为止我得到的最接近的结果:

SELECT s.*, p.*
FROM dbo_Student s LEFT JOIN
(SELECT p1.* 
 FROM dbo_Plan p1 INNER JOIN 
      (SELECT p2.student_id, MAX(p2.ID) As MaxID
       FROM dbo_Plan p2
       GROUP BY p2.student_id
      ) pAgg
      ON p1.student_id = pAgg.student_id 
         AND p1.ID = pAgg.MaxID
) p
ON s.id = p.student_id
WHERE Archived = FALSE
ORDER BY Name;

这假定最大 ID 是最新的计划(年份 DESC,版本 DESC)。它几乎总是有效,但它不是故障安全的。

【问题讨论】:

  • 你尝试过使用“内部”连接吗?
  • 您的子查询总共只返回一条记录。您想要一个返回一条记录的每个学生
  • @ErayBalkanli 是的,但是有些学生没有计划。

标签: sql ms-access


【解决方案1】:

鉴于您的原始查询暗示单个Year (ORDER BY Year DESC, Version DESC) 可能有多个Versions;我建议如下:

select dbo_student.*, b.*
from
    dbo_student left join
    (
        select a.* from dbo_plan a inner join
        (
            select q.student_id, q.year, max(q.version) as v
            from dbo_plan q inner join
            (
                select p.student_id, max(p.year) as y
                from dbo_plan p
                group by p.student_id
            ) s on q.student_id = s.student_id and q.year = s.y
            group by q.student_id, q.year
        ) t on
        a.student_id = t.student_id and 
        a.year = t.year and
        a.version = t.v
    ) b on dbo_student.id = b.student_id
where 
    archived = false
order by 
    name

最里面的查询获得最大Year每个Student_ID,然后父查询获得最大Version每个Year每个Student_ID,原始表连接到这样所有字段都可以输出。

【讨论】:

  • 是的,每年都有多个版本,我需要最近一年的最新版本 - 如果有计划的话。但是用你的代码我得到(翻译):不支持加入表达式。
  • @user3336208 抱歉 - 我省略了 group by 表达式,需要重新构建连接 - 我在上面编辑了我的答案。
【解决方案2】:

TOP 谓词适用于整个查询,而原始子查询未正确选择每个学生的记录。 从技术上讲,即使针对特定的 student_id 运行原始查询也无法正常工作。 也许它看起来只是因为许多 student_id 巧合地具有相同的“最近一年”,但内部子查询总是选择与最近一年排序的单个任意记录。这个查询的寓意:一个有效的查询不仅仅是返回看起来正确的代码。

以下版本与 Access SQL 兼容。最里面的 aggregate 子查询获取“每个学生”的最近一年 (GROUP BY p2.student_id)。然后下一个子查询获取与最近一年匹配的完整计划记录。

SELECT s.*, p.*
FROM dbo_Student s LEFT JOIN
    (SELECT p1.* 
     FROM pdbo_Plan p1 INNER JOIN
          (SELECT p2.student_id, 
                 pAgg2.MaxYear,
                 MAX(pAgg2.version) As MaxVersion
           FROM pdbo_Plan p2 INNER JOIN
                (SELECT p3.student_id, MAX(p3.year) As MaxYear
                 FROM dbo_Plan p3
                 GROUP BY p3.student_id
                ) pAgg2
                ON p2.student_id = pAgg2.student_id 
                   AND p2.year = pAgg2.MaxYear
           GROUP BY p2.student_id, pAgg2.MaxYear
          ) pAgg1
          ON p1.student_id = pAgg1.student_id 
             AND p1.year = pAgg1.MaxYear
             AND p1.version = pAgg1.MaxVersion
    ) p
    ON s.id = p.student_id
WHERE Archived = FALSE
ORDER BY Name;

【讨论】:

  • 我得到了同一个学生的多行。而不仅仅是最近的计划。我需要最新的年份和版本。
  • 感谢 Lee Mac 首先认识到版本要求。我还更新了代码以包含版本,现在基本上是相同的代码。
【解决方案3】:

我想你想要:

SELECT s.*, p.*
FROM dbo_Student s LEFT JOIN
     dbo_Plan p
     ON p.student_id = s.id AND
        p.year = (SELECT MAX(p1.year)
                  FROM dbo_Plan p1
                  WHERE p1.student_id = p.student_id
                 )
WHERE Archived = FALSE
ORDER BY Name;

【讨论】:

  • Access SQL 中不允许直接在 ON 表达式中使用子查询。 Access 确实允许 ON 表达式有一些变化,但比较表达式的两边都必须包含来自各自表的列。可以加入子查询,但只能作为源表。
猜你喜欢
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 2020-07-30
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
相关资源
最近更新 更多