SQL 分组查询中的非聚合列要求及实例解析
在 SQL 查询中,当我们对数据进行分组时,通常会用到 GROUP BY 子句。SQL 标准要求:所有非聚合列(即没有使用聚合函数的列)都必须出现在 GROUP BY 子句中,或者是聚合函数的结果。这篇文章通过一个实例来说明这个规则的原因及如何正确书写查询语句。
场景描述
我们有三张表:Customers(顾客信息)、Orders(订单信息)、OrderItems(订单项信息),它们分别包含以下字段:
-
Customers 表
cust_id:顾客 IDcust_name:顾客名称
-
Orders 表
order_num:订单号cust_id:顾客 ID(与Customers表关联)
-
OrderItems 表
order_num:订单号(与Orders表关联)quantity:商品数量item_price:商品单价
需求是返回每个顾客的 cust_name 和与之关联的订单号 order_num,以及每个订单的总价 OrderTotal,并按顾客名称和订单号进行排序。
数据示例
Customers 表:
| cust_id | cust_name |
|---|---|
| cust10 | andy |
| cust1 | ben |
| cust2 | tony |
| cust22 | tom |
| cust221 | an |
| cust2217 | hex |
Orders 表:
| order_num | cust_id |
|---|---|
| a1 | cust10 |
| a2 | cust1 |
| a3 | cust2 |
| a4 | cust22 |
| a5 | cust221 |
| a7 | cust2217 |
OrderItems 表:
| order_num | quantity | item_price |
|---|---|---|
| a1 | 1000 | 10 |
| a2 | 200 | 10 |
| a3 | 10 | 15 |
| a4 | 25 | 50 |
| a5 | 15 | 25 |
| a7 | 7 | 7 |
正确的 SQL 查询
为了实现需求,我们需要将三张表进行连接,并计算每个订单的总价。计算总价的方法是将 quantity 和 item_price 相乘,并对每个订单的所有项进行求和。最终的 SQL 查询如下:
SELECT c.cust_name, o.order_num, SUM(quantity * item_price) AS OrderTotal
FROM Customers c
JOIN Orders o ON c.cust_id = o.cust_id
JOIN OrderItems oi ON o.order_num = oi.order_num
GROUP BY c.cust_name, o.order_num
ORDER BY c.cust_name, o.order_num;
查询解析
- 连接三张表:通过
cust_id将Customers和Orders表连接,通过order_num将Orders和OrderItems表连接,获取顾客、订单和订单项的完整信息。 - 计算订单总价:使用
SUM(quantity * item_price)计算每个订单的总金额。 - 分组与排序:
GROUP BY c.cust_name, o.order_num按顾客名称和订单号分组,使每个分组对应一个顾客的一个订单,从而计算出每个订单的总金额。ORDER BY c.cust_name, o.order_num对结果按顾客名称和订单号排序。
查询结果
查询将返回顾客的姓名、订单号以及该订单的总价,并按顾客名称和订单号进行排序:
| cust_name | order_num | OrderTotal |
|---|---|---|
| andy | a1 | 10000 |
| ben | a2 | 2000 |
| tony | a3 | 150 |
| tom | a4 | 1250 |
| an | a5 | 375 |
| hex | a7 | 49 |
错误示例及解析
一个常见的错误查询示例如下:
SELECT c.cust_name, o.order_num, SUM(quantity * item_price) AS OrderTotal
FROM Customers c, Orders o, OrderItems oi
WHERE c.cust_id = o.cust_id AND o.order_num = oi.order_num
GROUP BY c.cust_name
ORDER BY c.cust_name, o.order_num;
错误原因:
- 这个查询中只在
GROUP BY子句中使用了cust_name,但order_num未包含在GROUP BY中,导致 SQL 无法确定如何处理order_num。 - 在 SQL 中,
GROUP BY子句中的列需要包含所有非聚合列(即未被聚合函数包裹的列)。否则,SQL 将无法知道如何处理这些非聚合列的值,从而导致错误。
1. 什么是聚合列和非聚合列?
-
聚合列:指的是在
SELECT语句中通过聚合函数(如SUM()、AVG()、MAX()、MIN()、COUNT()等)计算出的列。它们通常是针对分组数据进行的汇总统计,例如求某个分组中的所有值的和、平均值等。 -
非聚合列:在
SELECT语句中未使用聚合函数的列,即直接显示的列,没有进行任何聚合操作。这些列通常用于显示某个分组的特定属性。
2. 为什么非聚合列必须出现在 GROUP BY 子句中,或者是聚合函数的结果?
在分组查询中,SQL 标准要求所有出现在 SELECT 语句中的列要么是聚合函数的结果,要么出现在 GROUP BY 子句中。其原因如下:
-
确定性原则:在分组查询中,每个分组内可能包含多行数据,如果我们在
SELECT中选择了一个非聚合列,但没有将其包含在GROUP BY子句中,SQL 不知道应该选取哪个具体的值,因为每个分组中的该列值可能不同,这会导致不确定性。 -
保证数据一致性:当一个查询返回结果时,用户会希望每一行数据都是确定的、清晰的。如果没有将非聚合列放入
GROUP BY,则会出现难以理解的数据,可能导致数据含义不清或误导。
举例说明
假设有一个 sales 表,结构如下:
| id | region | sales_amount |
|---|---|---|
| 1 | East | 200 |
| 2 | East | 150 |
| 3 | West | 300 |
| 4 | West | 250 |
我们希望按 region 进行分组,求每个地区的总销售额。正确的 SQL 查询应该是:
SELECT region, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY region;
输出结果:
| region | total_sales |
|---|---|
| East | 350 |
| West | 550 |
在这个例子中,SUM(sales_amount) 是一个聚合列,而 region 是一个非聚合列。因为 region 出现在 GROUP BY 子句中,SQL 知道需要按 region 分组,然后对每组的数据进行汇总。
错误的写法
如果我们写成如下形式,将 id(非聚合列)放在 SELECT 语句中,却不出现在 GROUP BY 中:
SELECT id, region, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY region;
这样 SQL 会报错,因为每个 region 可能包含多行不同的 id,系统无法确定返回哪个 id。这就是 SQL 标准所要避免的“不确定性”问题。
如何解决?
如果确实需要某个非聚合列出现在查询结果中,那么我们有两种选择:
-
将非聚合列加入
GROUP BY子句中:如果id是我们希望按某个粒度分组的属性,可以将其加入GROUP BY。SELECT id, region, SUM(sales_amount) AS total_sales FROM sales GROUP BY id, region; -
使用聚合函数处理该列:如果想得到某个分组内的特定
id,可以使用聚合函数,如MAX(id)或MIN(id),以明确返回的值。SELECT MAX(id) AS example_id, region, SUM(sales_amount) AS total_sales FROM sales GROUP BY region;
总结
在 SQL 中,当我们进行分组查询时,所有出现在 SELECT 语句中的非聚合列都必须出现在 GROUP BY 子句中,或者使用聚合函数包裹。这样做的原因是,GROUP BY 子句能确保查询结果是确定的、清晰的。否则,SQL 将无法理解如何处理这些非聚合列,可能导致错误。
相关文章:
SQL 分组查询中的非聚合列要求及实例解析
在 SQL 查询中,当我们对数据进行分组时,通常会用到 GROUP BY 子句。SQL 标准要求:所有非聚合列(即没有使用聚合函数的列)都必须出现在 GROUP BY 子句中,或者是聚合函数的结果。这篇文章通过一个实例来说明这…...
Unity中实现战斗帧同步的高级技术
一、帧同步的基本原理 帧同步(Frame Synchronization)在网络游戏中指的是在每一帧上保证所有玩家所看到的游戏状态一致,而不是每个玩家单独计算自己的状态。实现帧同步通常需要每个客户端仅发送用户输入到服务器,并由服务器进行全…...
Qt 正则表达式提取文件中的 USB 设备 ID
Qt 正则表达式提取文件中的 USB 设备 ID flyfish 文档内容 Bus: 001 Device: 001 Description: 1d6b:0002 Linux Foundation 2.0 root hub Bus: 002 Device: 003 Description: 0e0f:0002 , Inc. USB Hub Bus: 002 Device: 002 Description: 0e0f:0003 , Inc. Mouse Bus: 002…...
使用 Python 和 OpenCV 实现摄像头人脸检测并截图
概述 在现代应用中,人脸检测是一项非常重要的技术,广泛应用于安全监控、身份验证等领域。本文将详细介绍如何使用 Python 和 OpenCV 库实现摄像头人脸检测并截图,并通过具体的代码示例来展示整个过程。 环境准备 在开始编写代码之前&#…...
【二叉搜素树】——LeetCode二叉树问题集锦:6个实用题目和解题思路
文章目录 计算布尔二叉树的值求根节点到叶节点的数字之和二叉树剪枝验证二叉搜索树二叉搜索树中第K小的元素二叉树的所有路径 计算布尔二叉树的值 解题思路: 这是一个二叉树的布尔评估问题。树的每个节点包含一个值,其中叶子节点值为 0 或 1࿰…...
【计算机视觉】FusionGAN
1. FusionGAN论文阅读 abreheret/FusionGAN: Pytorch implementation of "Generating a Fusion Image: One’s Identity and Another’s Shape" 1.1. WHY 在现实世界中,将对象或人物转换为期望的形状是一种常用技术,但现有的图像翻译方法在处理身份和形状时存在…...
问:SQL优化,七条实践总结?
SQL语句优化是数据库性能调优的重要部分,通过合理的优化可以显著提升查询速度和系统性能。文章总结几种常见SQL语句优化方法。 1. 优化Where子句的顺序 原则:表之间的连接条件应写在其他Where条件之前,能够过滤掉最大数量记录的条件应优先写…...
unity单例模式的不同声明(待完善
总结: 这段代码实现了一个泛型单例模式(Singleton Pattern),用于确保某个类(由泛型参数 T 指定)在整个应用程序中只有一个实例,并且在第一次访问时才创建该实例。该模式保证了该实例的全局唯一…...
大模型在蓝鲸运维体系应用——蓝鲸运维开发智能助手
本文来自腾讯蓝鲸智云社区用户: CanWay 背景 1、运维转型背景 蓝鲸平台从诞生之初,就一直在不遗余力地推动运维转型,让运维团队可以通过一体化PaaS平台,快速编写脚本,编排流程,开发运维工具,从被动地提供…...
vue2,vue3响应式的理解
vue2的话主要使用的是defineProperty对已有属性添加get,set,从而完成对数据的响应式控制,但每次需要for循环对属性进行遍历 function DefineReactive(target, key, value) {//存在多层嵌套的objectObserver(value);Object.defineReactive(target, key, {get() {retu…...
群控系统服务端开发模式-应用开发-前端退出功能
我们从未登录一直到退出,现在已经登录到操作,现在完成退出。退出有两种情况下会退出:第一种情况下是手动点击退出按钮,第二种情况下是登录过期时间到了自动退出的。 一、手动退出 因退出及个人信息页面都在公有页面,所…...
Web入门
Spring 官网:Spring | Home Spring是一个开源的Java企业级应用开发框架。Spring的主要目的是使Java EE(Java Platform, Enterprise Edition)开发更容易,并且通过提供一系列丰富的库和接口来促进良好编程实践,是…...
基于SpringBoot网上超市的设计与实现录像
基于SpringBoot网上超市的设计与实现录像 SpringBoot网上超市的设计与实现录像...
python爬虫(二)爬取国家博物馆的信息
import requests from bs4 import BeautifulSoup# 起始网址 url https://www.chnmuseum.cn/zx/xingnew/index_1.shtml # 用于存储所有数据 all_data [] page 1 global_index 1 # 定义全局序号变量并初始化为1 while True:html_url requests.get(url).textif requests.get…...
【mysql的当前读和快照读】
在MySQL中,尤其是InnoDB存储引擎中,读操作主要分为两种:当前读(Current Read)和快照读(Snapshot Read) 当前读 当前读每次读取的都是当前最新的数据。这种读操作在读取数据时不允许其他事务对这…...
[CKS] Audit Log Policy
最近准备花一周的时间准备CKS考试,在准备考试中发现有一个题目关于audit policy的题目。 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Netw…...
【Linux】-学习笔记03
第十一章-管理Linux软件包和进程 1.源码下载安装软件 1.1概念 源码文件:程序编写者使用C或C等语言编写的原始代码文本文件 源码文件使用.tar.gz或.tar.bz2打包成压缩文件 1.2特点 源码包可移植性好,与待安装软件的工作环境依赖性不大 由于有编译过程…...
Leetcode热题100-32 最长有效括号
Leetcode热题100-32 最长有效括号 1. 题目描述2. 解题思路动态规划栈解法 3. 代码实现动态规划栈解法 1. 题目描述 32 最长有效括号 2. 解题思路 动态规划 定义状态: 设 dp[i] 表示以位置 i 结尾的最长有效括号子串的长度。 状态转移方程: 遍历字符…...
【大数据学习 | HBASE】hbase的读数据流程与hbase读取数据
1. hbase的读数据流程 在解析读取流程之前我们还需要知道两个功能性的组件和HFIle的格式信息 HFILE 存储在hdfs中的hbase文件,这个文件中会存在hbase中的数据以kv类型显示,同时还会存在hbase的元数据信息,包括整个hfile文件的索引大小&…...
A027-基于Spring Boot的农事管理系统
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹 赠送计算机毕业设计600…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
