需用row_number()在分类内按库存升序编号再筛选:select category, name, stock from (select category, name, stock, row_number() over (partition by category order by stock asc) as rn from products) ranked where rn

用窗口函数 ROW_NUMBER() 按分类分组排序
直接 GROUP BY category 然后 MIN(stock) 只能拿到最小值,拿不到对应商品。必须保留每条商品记录,再在每个分类内按 stock 升序编号。关键不是聚合,是“分组内排序+筛选”。
实操建议:
- 用
ROW_NUMBER() OVER (PARTITION BY category ORDER BY stock ASC)生成序号,注意ASC(升序)才能让库存最少的排前面 - 别用
RANK()或DENSE_RANK():当多个商品库存相同时,它们会得到相同排名,可能突破 Top 5 数量;ROW_NUMBER()保证严格取前 5 条 - 如果分类数量少、数据量不大,子查询或 CTE 都可读性更好,避免嵌套过深
MySQL 8.0+ 和 PostgreSQL 写法基本一致
主流新版数据库都支持标准窗口函数,语法差异极小。但要注意 MySQL 5.7 及更早版本不支持,强行用会报错 ERROR 1064。
示例(通用写法):
SELECT category, name, stock
FROM (
SELECT category, name, stock,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY stock ASC) AS rn
FROM products
) ranked
WHERE rn
<p>注意:<code>products</code> 表名、<code>category</code>/<code>name</code>/<code>stock</code> 字段名需按实际调整;<code>rn</code> 是别名,不能在外部 WHERE 中直接写 <code>ROW_NUMBER()...</code></p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/ai/2953" title="Questrade"><img
src="https://img.php.cn/upload/ai_manual/001/246/273/177985773332906.png" alt="Questrade" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/ai/2953" title="Questrade" class="overflowclass">Questrade</a>
<p class="overflowclass">一款AI工具,主要用于使用 Questrade 浏览器平台为 openclaw.ai 工作流执行并监控股票交易,并配合 Yahoo Finance 进行交叉验证。当 Codex 被要求进行……,适合需要提升相关任务效率的用户。</p>
</div>
<a rel="nofollow" href="/ai/2953" title="Questrade" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<h3>SQL Server 需确认兼容级别 ≥ 120</h3>
<p>SQL Server 2012+ 支持窗口函数,但若数据库兼容级别设为 110(对应 SQL Server 2012 之前),<code>ROW_NUMBER()</code> 在 <code>OVER</code> 中使用 <code>PARTITION BY</code> 会失败,报错 <code>Incorrect syntax near 'ORDER'</code>。</p>
<p>检查并升级(如必要):</p>
- 查当前级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME(); - 升级命令(需 db_owner 权限):
ALTER DATABASE [your_db] SET COMPATIBILITY_LEVEL = 150; - 低版本绕行方案(不推荐):用
CROSS APPLY+TOP 5,性能差、语义复杂,易出错
有并列库存时要不要保留全部?
如果同一分类里第 5 名和第 6 名库存相同,业务上是否允许“并列入围”?这是容易被跳过的业务逻辑点。
ROW_NUMBER() 会强制截断到 5 条,而 RANK() 会把并列者全算进来(可能返回 6 条或更多)。没有银弹——得看需求:
- 要严格 Top 5 条 → 用
ROW_NUMBER() - 要所有库存 ≤ 第 5 小值的商品 → 用
RANK(),然后WHERE rk - 用
MIN(stock)先算出各分类第 5 小值再 JOIN,更啰嗦但可控性最强,适合审计场景
实际跑出来结果不对,先盯住这一条:到底是“取前 5 行”,还是“取库存值最小的前 N 个不同数值”——后者根本不是 Top 5,而是去重后找最小值。










