别再混淆了!SQL中GROUP BY和ORDER BY看似相似这些差异90%人没搞清

  • 时间:2025-11-11 19:59 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:在SQL中,GROUP BY和ORDER BY是数据处理(数据聚合与展示)的基本关键字。我们简单理解,GROUP BY是“按……分组”,将数据按指定列分组汇总;ORDER BY是“按……排序”,按指定列对结果升序或降序排列。字面上就能看出二者功能差异显著,具体说吧:GROUP BY用于数据聚合(将多行合并为分组统计结果),本质是数据压缩(将多行合并为分组统计结果,改变数据行数);ORDER BY用

在SQL中,GROUP BY和ORDER BY是数据处理(数据聚合与展示)的基本关键字。我们简单理解,GROUP BY是“按……分组”,将数据按指定列分组汇总;ORDER BY是“按……排序”,按指定列对结果升序或降序排列。字面上就能看出二者功能差异显著,具体说吧:GROUP BY用于数据聚合(将多行合并为分组统计结果),本质是数据压缩(将多行合并为分组统计结果,改变数据行数);ORDER BY用于结果排序(调整最终输出的顺序),本质是顺序调整(保持数据行数不变,仅改变展示顺序)。下面我们从GROUP BY和ORDER BY基础概念出发,通过模拟数据、执行过程和结果展示,逐一介绍GROUP BY和ORDER BY的单独应用、高级用法及结合场景示例,同时对GROUP BY和ORDER BY因理解偏差导致错误或性能问题做一些汇总,仅供参考。

一、基础概念与差异对比

逐项对比

GROUP BY

ORDER BY

基本功能

按指定列对数据分组,对每组计算聚合值(如:求和、计数)

对查询结果(原始数据或分组结果)按指定列排序(升序/降序)

操作对象

原始数据行(将多行合并为一组)

最终查询结果集(不改变数据行数,仅调整顺序)

执行阶段

比HAVING早,比WHERE晚

所有SQL操作的最后一步(在SELECT之后)

输出结果

行数减少(每组仅1行统计结果)

行数不变(与输入结果集行数一致)

常用搭配

聚合函数(COUNT/SUM/AVG/MAX/MIN)

排序方向(ASC升序/DESC降序,默认ASC)

语法限制

SELECT

列需为分组列或聚合函数

可使用SELECT中的别名、函数或表达式

二、模拟数据表

表1:products(商品表)

存储商品的分类、名称、价格和品牌信息,用于基础分组与排序演示。

id

category

name

price

brand

1

家电

冰箱

3000

海尔

2

家电

洗衣机

2500

美的

3

家电

空调

4000

格力

4

数码

手机

5000

苹果

5

数码

电脑

6000

联想

6

数码

平板

3000

华为

7

服装

衬衫

200

优衣库

8

服装

裤子

300

优衣库

9

数码

耳机

800

索尼

10

家电

电视

5500

小米

表2:sales(销售表)

存储商品的销售记录,包含日期、商品ID和销量,用于高级分组(如:按时间汇总)演示。

sale_id

product_id

sale_date

quantity

1

1

2024-01-05

5

2

1

2024-01-15

3

3

4

2024-01-08

10

4

5

2024-02-02

4

5

7

2024-02-10

20

6

8

2024-03-03

15

7

3

2024-03-08

6

8

6

2024-03-12

8

三、GROUP BY的单独应用

GROUP BY是分组聚合,先按指定列将数据划分为多个组,再对每组执行聚合计算。

1、单字段分组与聚合

需求:我们按商品分类(category)分组,统计每个分类的商品数量、平均价格和最高价格。

SQL实现

SELECT 
  category,  -- 分组列(必须出目前SELECT中)
  COUNT(*) AS product_count,  -- 统计每组商品数量
  AVG(price) AS avg_price,    -- 计算每组平均价格
  MAX(price) AS max_price     -- 计算每组最高价格
FROM products
GROUP BY category;  -- 按分类分组

执行过程

(1)读取原始数据:从products表获取10条商品记录。

(2)分组划分:按category字段将数据分为3组:

  • 家电组:包含冰箱、洗衣机、空调、电视(4条记录)
  • 数码组:包含手机、电脑、平板、耳机(4条记录)
  • 服装组:包含衬衫、裤子(2条记录)

(3)聚合计算:对每组应用聚合函数,得到统计结果。

执行结果

category

product_count

avg_price

max_price

家电

4

3750.00

5500

数码

4

3700.00

6000

服装

2

250.00

300

2、多字段分组

当单字段分组无法满足需求时,我们可通过多字段分组实现更细粒度的统计。

需求:我们按“分类+品牌”分组,统计每个品牌在对应分类下的商品数量和平均价格。

SQL实现

SELECT 
  category,
  brand,  -- 第二个分组列
  COUNT(*) AS brand_product_count,
  AVG(price) AS brand_avg_price
FROM products
GROUP BY category, brand;  -- 先按分类、再按品牌分组

执行过程

(1)多字段分组:先按category分组,再在每个分类内按brand细分:

  • 家电组内:海尔(1条)、美的(1条)、格力(1条)、小米(1条)
  • 数码组内:苹果(1条)、联想(1条)、华为(1条)、索尼(1条)
  • 服装组内:优衣库(2条)

(2)聚合计算:对每个“分类-品牌”子组执行统计。

执行结果

category

brand

brand_product_count

brand_avg_price

家电

海尔

1

3000.00

家电

美的

1

2500.00

家电

格力

1

4000.00

家电

小米

1

5500.00

数码

苹果

1

5000.00

数码

联想

1

6000.00

数码

华为

1

3000.00

数码

索尼

1

800.00

服装

优衣库

2

250.00

3、GROUP BY与CASE结合(动态分组)

我们通过CASE表达式定义动态分组条件,实现“自定义区间分组”(如:价格区间、等级划分)。

需求:我们按价格区间分组,统计每个区间的商品数量和总价格。

SQL实现

SELECT 
  -- 动态定义价格区间(分组条件)
  CASE 
    WHEN price < 1000 THEN '低价商品(<1000)'
    WHEN price BETWEEN 1000 AND 5000 THEN '中价商品(1000-5000)'
    ELSE '高价商品(>5000)' 
  END AS price_range,
  COUNT(*) AS range_count,  -- 区间商品数量
  SUM(price) AS range_total_price  -- 区间总价格
FROM products
GROUP BY price_range;  -- 按动态生成的区间分组

执行过程

(1)动态分组条件:通过CASE将每个商品分配到对应的价格区间:

  • 低价商品:衬衫(200)、裤子(300)、耳机(800)→ 3条
  • 中价商品:冰箱(3000)、洗衣机(2500)、空调(4000)、平板(3000)→ 4条
  • 高价商品:手机(5000)、电脑(6000)、电视(5500)→ 3条

(2)聚合计算:对每个区间执行统计。

执行结果

price_range

range_count

range_total_price

低价商品(<1000)

3

1300

中价商品(1000-5000)

4

12500

高价商品(>5000)

3

16500

4、ROLLUP/CUBE多级汇总(报表统计)

用于生成“小计+总计”的多级汇总数据,适合报表场景(如:按时间维度汇总销量)。

需求:我们按“月份-商品分类”分组,统计每月各分类的销量,并生成月度小计和总总计。

SQL实现(使用ROLLUP):

SELECT 
  TO_CHAR(s.sale_date, 'YYYY-MM') AS sale_month,  -- 提取销售月份
  p.category,
  SUM(s.quantity) AS total_quantity  -- 统计销量
FROM sales s
JOIN products p ON s.product_id = p.id  -- 关联商品表获取分类
GROUP BY ROLLUP(sale_month, category);  -- 生成逐级汇总(分类→月份→总计)

执行过程

(1)基础分组:先按sale_month分组,再在每月内按category细分,得到“月-分类”销量。

(2)逐级汇总

  • 第一级:每个“月-分类”的销量(如:2024-01的家电销量)
  • 第二级:每月的小计(如:2024-01的总销量,category为NULL)
  • 第三级:所有月份的总计(sale_month和category均为NULL)

执行结果(含汇总行):

sale_month

category

total_quantity

2024-01

家电

8

2024-01

数码

10

2024-01

NULL

18

2024-02

数码

4

2024-02

服装

20

2024-02

NULL

24

2024-03

家电

6

2024-03

数码

8

2024-03

服装

15

2024-03

NULL

29

NULL

NULL

71

5、GROUP BY与窗口函数结合(保留明细)

传统GROUP BY会丢失原始明细行,结合窗口函数(OVER (PARTITION BY))可在保留明细的同时展示分组统计结果。

需求:我们要查询所有商品信息,并显示该商品所在分类的平均价格。

SQL实现

SELECT 
  id,
  category,
  name,
  price,
  -- 按分类分组计算平均价格(窗口函数,不聚合行)
  AVG(price) OVER (PARTITION BY category) AS category_avg_price
FROM products;

执行过程

(1)窗口分组:按category对数据进行“逻辑分组”(不合并行,仅标记分组)。

(2)计算窗口值:对每个商品,计算其所在分组的平均价格并附加到该行。

执行结果(保留所有明细):

id

category

name

price

category_avg_price

1

家电

冰箱

3000

3750.00

2

家电

洗衣机

2500

3750.00

3

家电

空调

4000

3750.00

10

家电

电视

5500

3750.00

4

数码

手机

5000

3700.00

5

数码

电脑

6000

3700.00

...

...

...

...

...

四、ORDER BY的单独应用

ORDER BY是结果排序,不改变数据内容和行数,仅调整输出顺序。

1、单字段排序

需求:我们要查询所有商品,按价格从高到低(降序)排序。

SQL实现

SELECT 
  name,
  category,
  price,
  brand
FROM products
ORDER BY price DESC;  -- 按价格降序(DESC),默认升序(ASC)

执行过程

(1)读取原始数据:获取10条商品记录。

(2)排序操作:按price字段值从大到小排列所有记录(价格一样的行顺序随机,除非指定多字段排序)。

执行结果

name

category

price

brand

电脑

数码

6000

联想

电视

家电

5500

小米

手机

数码

5000

苹果

空调

家电

4000

格力

冰箱

家电

3000

海尔

平板

数码

3000

华为

洗衣机

家电

2500

美的

耳机

数码

800

索尼

裤子

服装

300

优衣库

衬衫

服装

200

优衣库

2、多字段排序(优先级排序)

当单字段排序存在“一样值”时,我们可通过多字段排序定义优先级(先按第一列排序,第一列一样的行再按第二列排序)。

需求:我们要求先按商品分类升序(A-Z)排序,同一分类内按价格降序排序。

SQL实现

SELECT 
  name,
  category,
  price,
  brand
FROM products
ORDER BY category ASC, price DESC;  -- 第一优先级:分类(升序),第二优先级:价格(降序)

执行过程

(1)一级排序:先按category升序分组(家电→数码→服装)。

(2)二级排序:在每个分类内部,按price降序排列(如家电分类内:电视5500→空调4000→冰箱3000→洗衣机2500)。

执行结果

name

category

price

brand

电视

家电

5500

小米

空调

家电

4000

格力

冰箱

家电

3000

海尔

洗衣机

家电

2500

美的

电脑

数码

6000

联想

手机

数码

5000

苹果

平板

数码

3000

华为

耳机

数码

800

索尼

裤子

服装

300

优衣库

衬衫

服装

200

优衣库

3、ORDER BY与CASE结合(条件排序)

我们通过CASE表达式定义“自定义排序逻辑”,满足特殊业务需求(如:优先展示指定分类、按状态优先级排序)。

需求:我们要求优先展示“数码”分类商品,其次是“家电”,最后是“服装”;同一分类内按价格升序排序。

SQL实现

SELECT 
  name,
  category,
  price,
  brand
FROM products
ORDER BY 
  -- 自定义分类优先级:数码(1)→家电(2)→服装(3)
  CASE category 
    WHEN '数码' THEN 1 
    WHEN '家电' THEN 2 
    ELSE 3 
  END ASC,
  price ASC;  -- 同优先级内按价格升序

执行过程

(1)条件优先级排序:通过CASE为每个分类分配“排序权重”(数码1<家电2<服装3),确保数码分类最先展示。

(2)二级排序:同一权重(同一分类)内,按price升序排列。

执行结果

name

category

price

brand

耳机

数码

800

索尼

平板

数码

3000

华为

手机

数码

5000

苹果

电脑

数码

6000

联想

洗衣机

家电

2500

美的

冰箱

家电

3000

海尔

空调

家电

4000

格力

电视

家电

5500

小米

衬衫

服装

200

优衣库

裤子

服装

300

优衣库

4、按函数/表达式排序

ORDER BY支持基于“计算结果”排序,如:字符串长度、日期格式化、数值运算等。

需求:我们要按商品名称的字符长度升序排序(短名称在前),长度一样则按名称升序。

SQL实现

SELECT 
  name,
  LENGTH(name) AS name_length,  -- 计算名称长度(辅助列,可选)
  category,
  price
FROM products
ORDER BY 
  LENGTH(name) ASC,  -- 按名称长度升序
  name ASC;          -- 长度一样时按名称升序

执行过程

(1)计算表达式值:对每个商品的name计算长度(如:“手机”长度2,“洗衣机”长度3)。

(2)按表达式排序:先按长度升序,再按名称本身升序。

执行结果

name

name_length

category

price

冰箱

2

家电

3000

空调

2

家电

4000

手机

2

数码

5000

电脑

2

数码

6000

平板

2

数码

3000

电视

2

家电

5500

衬衫

2

服装

200

裤子

2

服装

300

耳机

2

数码

800

洗衣机

3

家电

2500

5、ORDER BY与LIMIT结合(Top N查询)

通过ORDER BY排序后,用LIMIT截取前N条数据,实现“获取排名前N的结果”(如:Top 3高价商品)。

需求:我们要查询价格最高的3件商品,显示名称、分类和价格。

SQL实现

SELECT 
  name,
  category,
  price
FROM products
ORDER BY price DESC  -- 先按价格降序
LIMIT 3;  -- 截取前3条

执行过程

(1)排序:按price降序排列所有商品(电脑6000→电视5500→手机5000→...)。

(2)截取:保留排序后的前3条记录。

执行结果

name

category

price

电脑

数码

6000

电视

家电

5500

手机

数码

5000

6、按JSON/数组字段排序(部分数据库特有)

在支持JSON/数组的数据库(如:PostgreSQL、MySQL 8.0+)中,ORDER BY可直接按JSON字段或数组元素排序。

需求:假设products表新增specJSON字段(存储商品规格,如:{"screen_size": "6.7英寸", "battery": "5000mAh"}),按屏幕尺寸(数值部分)降序排序数码商品。

SQL实现(PostgreSQL示例):

SELECT 
  name,
  spec->>'screen_size' AS screen_size,  -- 提取JSON中的屏幕尺寸
  price
FROM products
WHERE category = '数码'  -- 仅筛选数码商品
ORDER BY 
  -- 提取屏幕尺寸的数值部分(如:“6.7英寸”→6.7)并排序
  (REGEXP_REPLACE(spec->>'screen_size', '[^0-9.]', '', 'g'))::NUMERIC DESC;

执行过程

(1)筛选数据:仅保留分类为“数码”的商品。

(2)提取 JSON 字段:从spec中提取screen_size(如:6.7英寸)。

(3)处理数值:通过正则表达式去除非数值字符(保留数字和小数点),转换为数值类型。

(4)排序:按处理后的屏幕尺寸数值降序排列。

执行结果(模拟数据):

name

screen_size

price

电脑

16.0英寸

6000

平板

11.0英寸

3000

手机

6.7英寸

5000

耳机

-

800

五、GROUP BY与ORDER BY的结合应用

GROUP BY与ORDER BY结合是SQL中的常用场景,是先分组聚合,再对聚合结果排序,用于展示“分组统计后的排名”(如:各分类销售额排名、各部门平均工资排序)。

1、分组后按聚合结果排序

需求:我们按商品分类分组,统计每个分类的商品数量和总价格,再按总价格降序排序(展示分类贡献度)。

SQL实现

SELECT 
  category,
  COUNT(*) AS product_count,  -- 分类商品数量
  SUM(price) AS total_price   -- 分类总价格(聚合结果)
FROM products
GROUP BY category  -- 第一步:分组聚合
ORDER BY total_price DESC;    -- 第二步:按聚合结果排序

执行过程

(1)执行GROUP BY:按category分组并计算聚合值,得到基础分组结果:

category

product_count

total_price

家电

4

15000

数码

4

14800

服装

2

500

(2)执行ORDER BY:按total_price降序排序分组结果,调整展示顺序。

执行结果

category

product_count

total_price

家电

4

15000

数码

4

14800

服装

2

500

2、多列分组后按多级排序

需求:我们按“分类+品牌”分组,统计每个品牌的商品数量和平均价格,再按分类升序、平均价格降序排序(展示同分类内各品牌的价格水平)。

SQL实现

SELECT 
  category,
  brand,
  COUNT(*) AS brand_count,
  AVG(price) AS brand_avg_price
FROM products
GROUP BY category, brand  -- 多列分组(分类→品牌)
ORDER BY 
  category ASC,  -- 一级排序:分类升序
  brand_avg_price DESC;  -- 二级排序:品牌平均价格降序

执行过程

(1)多列分组:先按category分组,再在每个分类内按brand细分,计算每个“分类-品牌”的聚合值:

  • 家电-小米:1件,均价5500;家电-格力:1件,均价4000;...
  • 数码-联想:1件,均价6000;数码-苹果:1件,均价5000;...
  • 服装-优衣库:2件,均价250;

(2)多级排序:先按category升序(家电→数码→服装),同一分类内按brand_avg_price降序。

执行结果

category

brand

brand_count

brand_avg_price

家电

小米

1

5500.00

家电

格力

1

4000.00

家电

海尔

1

3000.00

家电

美的

1

2500.00

数码

联想

1

6000.00

数码

苹果

1

5000.00

数码

华为

1

3000.00

数码

索尼

1

800.00

服装

优衣库

2

250.00

3、分组后按占比排序(百分比排序)

需求:我们按商品分类分组,统计每个分类的总价格占全表总价格的比例,再按比例降序排序(展示分类贡献占比)。

SQL实现

SELECT 
  category,
  SUM(price) AS category_total,
  -- 计算分类总价格占全表总价格的比例(保留2位小数)
  ROUND(
    SUM(price) / (SELECT SUM(price) FROM products) * 100, 
    2
  ) AS price_ratio
FROM products
GROUP BY category  -- 分组统计分类总价格
ORDER BY price_ratio DESC;  -- 按占比降序

执行过程

(1)计算全表总价格:子查询(SELECT SUM(price) FROM products)得到全表总价格30300(15000+14800+500)。

(2)分组聚合:按category计算每个分类的总价格和占比:

  • 家电占比:15000/30300≈49.50%
  • 数码占比:14800/30300≈48.84%
  • 服装占比:500/30300≈1.65%

(3)按占比排序:按price_ratio降序展示结果。

执行结果

category

category_total

price_ratio

家电

15000

49.50

数码

14800

48.84

服装

500

1.65

4、分组Top N + 全局排序

需求:我们要求先获取每个分类中价格最高的2件商品(分组Top 2),再对这些商品按价格全局降序排序(展示所有高价值商品的整体排名)。

SQL实现

-- 子查询:获取每个分类的Top 2高价商品
WITH category_top2 AS (
  SELECT 
    category,
    name,
    price,
    -- 按分类分组,对价格降序排名(ROW_NUMBER()不处理并列,若需允许并列排名,我们应改用RANK()或DENSE_RANK())
    ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) AS rn
  FROM products
)
-- 外层查询:筛选Top 2并全局排序
SELECT 
  category,
  name,
  price
FROM category_top2
WHERE rn <= 2  -- 保留每个分类的前2名
ORDER BY price DESC;  -- 全局按价格降序

执行过程

(1)子查询(分组排名):按category分组,对每组内的商品按价格降序分配排名(rn):

  • 家电组:电视(5500,rn=1)、空调(4000,rn=2)、冰箱(3000,rn=3)、洗衣机(2500,rn=4)
  • 数码组:电脑(6000,rn=1)、手机(5000,rn=2)、平板(3000,rn=3)、耳机(800,rn=4)
  • 服装组:裤子(300,rn=1)、衬衫(200,rn=2)

(2)筛选 Top 2:保留rn <= 2的记录(共:3分类×2件=6条记录)。

(3)全局排序:对筛选后的6条记录按price降序排列,得到最终全局排名。

执行结果

category

name

price

数码

电脑

6000

家电

电视

5500

数码

手机

5000

家电

空调

4000

服装

裤子

300

服装

衬衫

200

5、ROLLUP汇总后排序(报表场景)

需求:我们要求按“年份-月份-分类”分组统计销量,生成多级汇总(月小计、年小计、总计),并按时间和销量排序(便于报表展示)。

SQL实现

SELECT 
  EXTRACT(YEAR FROM s.sale_date) AS sale_year,  -- 提取年份
  EXTRACT(MONTH FROM s.sale_date) AS sale_month,  -- 提取月份
  p.category,
  SUM(s.quantity) AS total_quantity
FROM sales s
JOIN products p ON s.product_id = p.id
GROUP BY ROLLUP(sale_year, sale_month, category)  -- 三级汇总:年→月→分类
ORDER BY 
  sale_year ASC NULLS LAST,  -- 年份升序(NULL放最后,即总计行)
  sale_month ASC NULLS LAST,  -- 月份升序
  total_quantity DESC;  -- 同时间内按销量降序

执行过程

(1)多级分组汇总:通过ROLLUP生成四级结果:

  • 明细级:每个“年-月-分类”的销量
  • 月小计:每个“年-月”的总销量(category为NULL)
  • 年小计:每年的总销量(sale_month和category为NULL)
  • 总计:所有年份的总销量(sale_year、sale_month、category为NULL)

(2)排序优化:按sale_year→sale_month升序(确保时间顺序),同时间内按销量降序(突出高销量分类),NULL值放最后(避免汇总行干扰明细排序)。

执行结果(简化版):

sale_year

sale_month

category

total_quantity

2024

1

数码

10

2024

1

家电

8

2024

1

NULL

18

2024

2

服装

20

2024

2

数码

4

2024

2

NULL

24

2024

NULL

NULL

71

NULL

NULL

NULL

71

六、GROUP BY与ORDER BY的常见误区与疑难解析

1、常见误区与错误示例解析

(1)混淆GROUP BYORDER BY的执行顺序

错误认识:我们错误认为ORDER BY可以影响GROUP BY的分组逻辑(如:先排序再分组)。

实际逻辑:GROUP BY先执行,ORDER BY仅排序分组后的结果,与原始数据的顺序无关。

错误示例

-- 意图:先按价格排序,再按分类分组(期望每组保留最高价格商品)
SELECT category, name, price
FROM products
ORDER BY price DESC  -- 错误:ORDER BY后执行,不影响分组
GROUP BY category;

错误缘由:SQL语法规定GROUP BY必须在ORDER BY之前,且分组逻辑与排序无关。

正确做法:我们使用窗口函数(如:ROW_NUMBER())实现“每组取最高价格商品”。

(2)SELECT列与GROUP BY列不匹配

错误认识:我们错误地认为SELECT中可以包含非分组列或非聚合函数(如:直接引用原始字段)。

实际限制:SELECT中的列必须是GROUP BY的分组列或聚合函数(否则数据库无法确定取哪一行的值)。

错误示例

-- 错误:SELECT包含非分组列name(未在GROUP BY或聚合函数中)
SELECT category, name, AVG(price) AS avg_price
FROM products
GROUP BY category;

错误缘由:name不是分组列,同一分类下有多个名称,数据库无法确定返回哪个值。

正确做法:若需保留明细,请使用窗口函数而非GROUP BY。

(3)过度依赖ORDER BY进行去重

错误认识:通过ORDER BY排序后用LIMIT 1去重(如:获取每个分类的第一个商品)。

潜在风险:未分组时,ORDER BY无法保证“每个分类仅出现一次”,可能返回重复分类。

不推荐示例

-- 风险:可能返回重复分类(如:多个家电商品)
SELECT category, name
FROM products
ORDER BY category, price
LIMIT 3;

正确做法:请使用DISTINCT ON(PostgreSQL)或窗口函数实现分组去重。

2、分组排序与性能优化

(1)大数据量下的分组排序优化

当处理百万级以上数据时,GROUP BY + ORDER BY可能因全表扫描和排序导致性能瓶颈,我们需通过索引和语法优化提升效率。

优化:联合索引

我们对分组列和排序列创建联合索引,减少排序和分组的计算量:

-- 我们为products表创建(category, price)联合索引
CREATE INDEX idx_category_price ON products (category, price);

-- 优化后查询(可利用索引快速分组和排序)
SELECT 
  category,
  COUNT(*) AS count,
  MAX(price) AS max_price
FROM products
GROUP BY category
ORDER BY max_price DESC;

(2)分组排序中的并列处理

当排序字段存在一样值时(如:两个商品价格一样),ROW_NUMBER()、RANK()、DENSE_RANK()会产生不同结果,我们需根据业务选择。

示例:我们按分类查询价格排名(处理并列)

SELECT 
  category,
  name,
  price,
  ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) AS rn,  -- 不并列,序号唯一
  RANK() OVER (PARTITION BY category ORDER BY price DESC) AS rnk,       -- 并列跳号(如:1,1,3)
  DENSE_RANK() OVER (PARTITION BY category ORDER BY price DESC) AS drnk  -- 并列不跳号(如:1,1,2)
FROM products;

结果:家电分类部分

category

name

price

rn

rnk

drnk

家电

电视

5500

1

1

1

家电

空调

4000

2

2

2

家电

冰箱

3000

3

3

3

家电

洗衣机

2500

4

4

4

3、跨数据库的语法差异

不同数据库对GROUP BY和ORDER BY的高级功能支持存在差异,我们需注意兼容性:

功能

MySQL 8.0+

PostgreSQL

SQL Server

ROLLUP

/CUBE

支持

支持

支持

DISTINCT ON

不支持

支持(特有)

不支持

JSON字段排序

支持(JSON_EXTRACT)

支持(->>操作符)

支持(JSON_VALUE)

窗口函数 + 分组

支持

支持

支持(2012+)

ORDER BY

位置别名

支持

支持

支持

七、总结

GROUP BY和ORDER BY是我们写SQL处理数据时的左膀右臂:

  • GROUP BY聚合,通过分组将多行数据压缩为统计结果,应用于数据分析和报表生成等等场景,它的高级用法(ROLLUP、CASE动态分组、窗口函数结合)能够满足我们复杂的汇总需求。
  • ORDER BY排序,通过单字段、多字段或条件排序调整结果顺序,它的高阶用法(函数排序、Top N查询、JSON排序)可协助我们实现灵活的结果展示。
  • GROUP BY和ORDER BY结合时,遵循“先聚合后排序”的逻辑,广泛应用于“分组统计+排名展示”场景(如:各区域销售额排名、各部门绩效排序等)。

注意事项

(1)执行顺序不可颠倒:GROUP BY永远先于ORDER BY执行,ORDER BY只能排序GROUP BY后的结果,无法影响分组逻辑。

(2)ORDER BY可使用的字段

  • 分组列(如:category、brand)
  • 聚合函数(如:SUM(price)、COUNT(*))
  • SELECT中定义的别名(如:total_quantity、price_ratio)
  • 表达式或函数(如:LENGTH(name)、EXTRACT(YEAR FROM date))

(3)性能优化

  • 对GROUP BY的分组列和ORDER BY的排序列我们创建联合索引(如:(category, price)),减少排序和分组的计算开销。
  • 大数据量下,避免SELECT *配合GROUP BY,我们仅保留必要的分组列和聚合函数,减少数据处理量。
  • 复杂排序(如:CASE表达式、函数排序)可能导致性能下降,我们提议提前通过计算列或生成列优化。

(4)数据库兼容性

  • 基础用法(单字段分组、单字段排序)在所有数据库中通用。
  • 高级功能(ROLLUP/CUBE、JSON排序、DISTINCT ON)存在数据库差异:
    • ROLLUP在MySQL 8.0+、PostgreSQL、SQL Server中支持;
    • DISTINCT ON是PostgreSQL 特有语法;
    • JSON排序在MySQL 8.0+、PostgreSQL中支持较好。
  • 全部评论(0)
最新发布的资讯信息
【系统环境|】最低 2 美元,这 55 款 macOS & Windows 应用一次全都入手(2025-11-11 22:01)
【系统环境|】SCI期刊对论文图片有哪些要求?(2025-11-11 22:00)
【系统环境|】论文缩写大全,拿走不谢(2025-11-11 22:00)
【系统环境|】阿甘正传高频词整理 GRE托福四六级词汇整理(2025-11-11 21:59)
【系统环境|】矢量图形编辑应用程序-WinFIG(2025-11-11 21:59)
【系统环境|】Figma上市首日暴涨250%的深层逻辑:为什么AI时代协作平台更加不可替代?(2025-11-11 21:58)
【系统环境|】FigJam是什么?一文读懂在线白板软件的方方面面!(2025-11-11 21:58)
【系统环境|】在windows上有什么好用的书写白板软件?(2025-11-11 21:57)
【系统环境|】Docker基础应用之nginx(2025-11-11 21:57)
【系统环境|】VS Code 新手必装插件清单(2025-11-11 21:56)
手机二维码手机访问领取大礼包
返回顶部