如何让Access中first()与last()函数返回可靠结果?附min()/max()不适用场景说明
first()/last() 的随机性问题 如果你在 Access 里用 first() 或 last() 函数时发现结果不稳定,那不是你操作错了——微软文档明确说了,这俩聚合函数返回的记录是随机的,因为默认情况下查询返回的记录没有固定顺序(除非加 ORDER BY)。但坑人的是,作为聚合函数,ORDER BY 只能作用于经过聚合处理的字段,想直接加来固定顺序根本行不通。
有人可能会说,单表查询不都是按主键顺序返回吗?但这只是 Access 的默认行为,没有官方保证,换个场景(比如表结构变更、数据量变大)就可能失效,风险很高。
之前有文章提到两种解决思路,但没给具体代码,我来补上可直接复用的 SQL 示例,针对你要「获取某字段最值对应记录的其他字段」的需求(比如拿每个客户首次旅行的地点,而不是最小的地点名称):
方案一:子查询直接关联最值字段
这种方法不需要额外创建查询,用嵌套子查询先找到每个客户的最早旅行日期,再关联原表拿到对应的地点:
SELECT t.Customer, t.Location AS FirstTourLocation FROM Tours t WHERE t.TourDate = ( SELECT MIN(TourDate) FROM Tours WHERE Customer = t.Customer );
如果你的日期字段可能有重复(比如同一个客户同一天有多个旅行记录),可以再加主键判断来确保唯一性:
SELECT t.Customer, t.Location AS FirstTourLocation FROM Tours t WHERE t.TourID = ( SELECT TOP 1 TourID FROM Tours WHERE Customer = t.Customer ORDER BY TourDate ASC, TourID ASC );
方案二:先建聚合查询再关联
先创建一个只保留「客户 ID + 最早旅行日期」的聚合查询(比如命名为 qry_CustomerFirstTour):
SELECT Customer, MIN(TourDate) AS FirstTourDate FROM Tours GROUP BY Customer;
再把这个查询和原表关联,获取完整的首次旅行记录:
SELECT t.* FROM Tours t INNER JOIN qry_CustomerFirstTour sub ON t.Customer = sub.Customer AND t.TourDate = sub.FirstTourDate;
为什么不能直接用 min()/max() 替代?
很多资料说用 min() 或 max() 替换 first()/last(),但这只适用于「获取字段本身的最值」(比如最小的地点名称),完全满足不了你要「拿最值对应记录的其他字段」的需求——这也是你原来的代码 (SELECT first(location) from [Tours] where [Customer] = ID_Customer) 不稳定的原因:没有固定排序,返回的 location 是随机的,大概率不是你要的首次旅行地点。
内容的提问来源于stack exchange,提问作者NewSites

