MySQL 实战:跨表排序 + 指定类型置顶四种写法

0 阅读3分钟

前言

日常开发经常碰到两类排序需求:

  1. 跨表排序:依据一张表的查询字段,控制另外一张业务表结果集排序;
  2. 固定置顶:指定某一类数据强制排在列表最前面,剩余数据按原有规则排序。

很多新手只会单独单表排序,遇到关联 + 置顶组合需求就无从下手,本文结合实战场景,由浅入深梳理落地方案。

一、场景铺垫

两张业务表:

  • sort_config:排序配置表,存储商品自定义权重,goods_id关联商品主键、weight排序权重;
  • goods:商品主表,id主键、type商品类型、name商品名称、price售价。

需求:根据sort_config筛选有效配置的权重排序商品,同时type=1(热门商品)强制置顶。

二、需求 1:A 表条件驱动 B 表排序(JOIN 关联排序)

核心思路:两表关联后,ORDER BY使用关联出来的 A 表字段完成排序。

基础 SQL

sql

SELECT g.*
FROM goods g
INNER JOIN sort_config sc ON g.id = sc.goods_id
WHERE sc.status = 1 -- A表筛选条件
ORDER BY sc.weight DESC; -- 使用A表权重给B表排序

要点说明

  1. INNER JOIN:只带出有配置权重的商品;LEFT JOIN 需要自行处理无权重数据默认排序;
  2. WHERE 筛选 A 表数据,筛选后再依托 A 表字段完成整体排序;
  3. 适用:配置表动态维护排序权重,前端不用传排序字段,由数据库配置控制。

三、需求 2:指定类型置顶 4 种常用方案

方案 1:FIELD 函数(推荐 MySQL5.7+,多值固定顺序)

FIELD(字段,置顶值)配合DESC实现置顶,多类型自定义排序顺序。

sql

SELECT g.*
FROM goods g
JOIN sort_config sc ON g.id = sc.goods_id
WHERE sc.status = 1
ORDER BY
    FIELD(g.type,1) DESC, -- type=1置顶
    sc.weight DESC; -- 剩余按配置权重排序

多类型固定顺序(1>3>2)写法:

sql

ORDER BY FIELD(g.type,1,3,2),sc.weight DESC

方案 2:布尔表达式置顶(极简写法)

利用 MySQL 布尔1/0特性,条件成立 = 1,倒序置顶。

sql

ORDER BY g.type=1 DESC,sc.weight DESC

多类型置顶:

sql

ORDER BY g.type IN(1,3) DESC,sc.weight DESC

方案 3:CASE WHEN(兼容低版本 MySQL,通用性最强)

适配所有 MySQL 版本,自定义排序分值,置顶数据分值设 0,其余设大值。

sql

SELECT g.*
FROM goods g
JOIN sort_config sc ON g.id = sc.goods_id
WHERE sc.status = 1
ORDER BY
    CASE WHEN g.type =1 THEN 0 ELSE 1 END ASC,
    sc.weight DESC;

方案 4:数据库冗余排序字段(大数据量最优)

数据量大、千万级分页场景,不推荐函数排序,新增top_sort int字段,置顶数据存 0,普通数据存 9999。

sql

ALTER TABLE goods ADD top_sort INT DEFAULT 9999;
-- type=1数据更新为0
UPDATE goods SET top_sort=0 WHERE type=1;

-- 查询SQL(可命中索引)
SELECT g.*
FROM goods g
JOIN sort_config sc ON g.id = sc.goods_id
WHERE sc.status = 1
ORDER BY g.top_sort ASC,sc.weight DESC;

✅ 优点:字段可建索引,分页查询性能远高于函数排序,海量数据首选。

四、四种方案选型总结

表格

方案适用场景优缺点
FIELD 函数MySQL5.7+、中小数据量、多值自定义顺序写法简洁,无法走索引
布尔表达式单类型快速置顶、临时查询代码最短,不支持复杂自定义顺序
CASE WHEN全版本兼容、复杂分值排序通用性强,同样不能使用索引
冗余字段百万级 + 大数据分页、高频查询可建索引,性能最优,需要维护字段

五、拓展优化:开发避坑

  1. 函数排序无法走索引:列表分页量大时,尽量使用冗余字段方案;
  2. LEFT JOIN 空值处理:左连接无配置权重数据,可用IFNULL(sc.weight,0)兜底默认权重;
  3. 动态排序:若排序字段由配置表动态返回字段名,Java 后端拼接 SQL,不要在 SQL 内动态解析字段。

结语

跨表排序 + 置顶是后台列表通用需求,优先小数据用FIELD快速实现,大数据提前设计排序冗余字段,从 SQL 层面提前规避后期分页慢问题。

需要配套 Java 业务代码版本可以在评论区留言。