SQL中无原生VLOOKUP模糊匹配(TRUE参数),需用LEFT JOIN结合子查询或窗口函数实现“≤查找值的最大匹配”:先按匹配列降序排序,再用ROW_NUMBER()取首个满足条件的记录。

什么是“SQL里的VLOOKUP模糊匹配”?
Excel 的 VLOOKUP 用 TRUE 参数时会找“小于等于查找值的最大匹配项”,即向后取最近的下界——这不是正则或全文搜索,而是有序数据上的**上界/下界定位**。SQL 没有原生 VLOOKUP(..., TRUE) 等价物,但可以用窗口函数 + 排序 + 条件过滤逼近它,前提是查找列(比如时间、编号、价格)天然有序且可比较。
LAG 和 LEAD 只能看相邻行,不够用
很多人第一反应是用 LAG 或 LEAD 去“拉一行上来”,但这只能获取固定偏移的邻近值,无法动态找到“≤目标值的最大那个”。真正需要的是:对每个查询点,在有序主表中定位其“前一个有效锚点”。
-
LAG要求你知道偏移量(比如LAG(price, 1)),但模糊匹配的偏移是未知的 - 如果主表和查找表无严格一一对应(例如按时间匹配费率表),
LAG/LEAD无法跨行跳转 - 正确思路是:先
JOIN再用窗口函数筛选,或用ROW_NUMBER()+ 子查询
用 ROW_NUMBER() + ORDER BY ... DESC 实现“向下取最大 ≤ X”
核心技巧:对主表按匹配列降序排序,对每个查找值,取满足 lookup_col 的第一条(即最大的那个)。常用写法是子查询 + <code>ROW_NUMBER(),而不是直接窗口函数。
清理、标准化、验证并汇总杂乱的 Excel 工作簿。当 Codex 需要处理 `.xlsx`、`.xls`、`.xlsm` 或 `.csv` 格式的数据时使用,包括:统一表头格式、删除空白行与空白列、修剪文本内容、去重记录、检测数据质量问题、拆分或合并工作表、生成清洗后的工作簿,以及为业务电子表格生成审计摘要。
SELECT t1.id, t1.ts,
(SELECT rate
FROM rates r
WHERE r.effective_date <= t1.ts
ORDER BY r.effective_date DESC
LIMIT 1) AS matched_rate
FROM events t1;
这个写法在 PostgreSQL / MySQL 8.0+ / SQL Server 中都成立。注意:
- 必须给
rates.effective_date加索引,否则每次子查询都是全表扫 - 不能用
LEFT JOIN直接关联,因为ON r.effective_date 会产生笛卡尔积 - 如果数据库不支持
LIMIT(如 SQL Server),改用TOP 1;Oracle 用ROWNUM = 1(需嵌套)
用 LAST_VALUE + RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 是陷阱
有人尝试用 LAST_VALUE(rate) OVER (ORDER BY effective_date RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 模拟,但这是错的——RANGE 在多数引擎里只支持 UNBOUNDED 或 CURRENT ROW,不支持动态“≤当前事件时间”的范围;而且 LAST_VALUE 默认是 RANGE,不是 ROWS,行为不可控。
- PostgreSQL 对
RANGE的日期支持有限,实际会退化为ROWS,失去语义 - 即使语法通过,结果也常漏掉非精确匹配项,尤其当主表有空缺区间时
- 真正可靠的方案仍是带
WHERE + ORDER BY + LIMIT/TOP的标量子查询,或使用LATERAL JOIN(PostgreSQL)

















