尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SQL统计查询与嵌套查询实验:聚合分组、连接子查询避坑
简介数据库实验5嵌套查询.doc 面向高校数据库课程学习者是一份围绕 SELECT 统计查询、常用统计函数、连接查询与嵌套查询四个层级组织的实验报告可用于课堂实验提交、期末复习与 SQL 语法自查。压缩包内含 1 个 doc 文件约 642KB按实验目的、实验内容、实践结论、实验思考等板块成文打开即可阅读。文档以 CPXS 数据库为背景逐条列出客户数目统计、库存总量求和、按客户分组计数、单价区间筛选等十余道操作的语句范例并演示由比较运算符、IN 等谓词构成的子查询与相关子查询写法。已有 931 人学习读者可据此对照分组与 HAVING 过滤的差异理解由内到外的查询拆解顺序在动手练习时快速排查语法与逻辑错误。1. 从一份跑得通却对不上数的查询清单说起数据库实验做到第五个卡点往往不在写不出 SELECT而是语句跑通了、结果跟标准答案对不上。这份实验五围绕一个客户—产品—销售的 CPXS 库展开重心是数据统计查询和嵌套查询两条线一条用 COUNT、SUM、MAX、MIN 配合 GROUP BY、HAVING 做汇总一条用子查询把“先算出一个值、再拿这个值去筛”的思路落成 SQL。它适合正在交数据库课设或实验报告的学生也适合需要给新人出一套查询练习题的从业者。十四道题看着零散其实覆盖的是聚合、连接、子查询三类基本功把它们按考点重新排一遍整套实验就从“抄语句”变成“能讲清为什么这么写”。2. 数据模型与题目分层三张表撑起十四道查询2.1 三张核心表的字段语义与约束做这类查询实验第一件事不是写 SQL是把表结构和约束确认清楚。约束决定了你能不能用“一行一个客户”“一行一个产品”这种假设去推结果也决定了 GROUP BY 出来的计数到底在数什么。项目里出现过的字段有限客户表有编号、名称、所在城市、联系电话产品表有编号、名称、单价、库存量销售表有客户编号、产品编号、订购数量。把这几个字段落成可执行的结构后面十四道题才有稳定的落脚点。-- CPXS 库的最小可用结构够支撑统计、连接、嵌套三类查询 CREATE TABLE CUSTOMER ( CNO CHAR(4) NOT NULL, -- 客户编号主键 CNAME VARCHAR(40) NOT NULL, -- 客户公司名称 SITE VARCHAR(20) NOT NULL, -- 所在城市 TELE VARCHAR(20), -- 联系电话允许为空 PRIMARY KEY (CNO) ); CREATE TABLE PRODUCT ( PCODE CHAR(4) NOT NULL, -- 产品编号主键 PNAME VARCHAR(40) NOT NULL, -- 产品名称 PRICE DECIMAL(8,2) NOT NULL, -- 单价两位小数 STOCKS INT NOT NULL, -- 库存量 PRIMARY KEY (PCODE) ); CREATE TABLE SALE ( CNO CHAR(4) NOT NULL, -- 客户编号外键指向 CUSTOMER PCODE CHAR(4) NOT NULL, -- 产品编号外键指向 PRODUCT OQUANTITY INT NOT NULL, -- 订购数量 PRIMARY KEY (CNO, PCODE), -- 联合主键同一客户对同一产品只有一条记录 FOREIGN KEY (CNO) REFERENCES CUSTOMER(CNO), FOREIGN KEY (PCODE) REFERENCES PRODUCT(PCODE) );上面这段 DDL 里真正影响结果的是 SALE 的联合主键。它意味着一张销售表里“客户 A 买产品 B”只会出现一行订购数量记在这一行上。于是COUNT(PCODE)在这个表里数出来的是“涉及多少个不同产品”COUNT(*)数的是“有多少条订购记录”两者在 SALE 上是同一个值但换个场景就不一定了。很多同学写第 8 题时把COUNT(PCODE)当成“订购总量”用结果条数对了、语义错了答辩一问就露出破绽。TELE 允许为空这一点也值得留意。电话号码缺失在真实数据里太常见而COUNT(TELE)不会把 NULL 算进去COUNT(*)会。这两个函数在同一张表上给出不同数字是排查阶段最容易被误判成“数据丢了”的地方。我一般会建议在实验开始前先跑一遍SELECT COUNT(*), COUNT(TELE) FROM CUSTOMER;把两个数字的差异记在纸上后面遇到计数对不上时先回头看这张表里到底有没有空值。提示如果手头的库已经把“上海”“美美”这类具体取值写死照抄语句时记得替换成自己库里实际存储的值字符串比较是逐字符匹配的差一个字就是零行。2.2 把十四道题按考点归成三组十四道题摊开看像十四种写法归一下类其实只有三组。分组的依据不是题号顺序而是“过滤动作发生在哪一步”是在分组前筛行还是在分组后筛组还是先算出一个中间结果再拿它当条件。按这个标准重新排列实验的脉络会清楚很多也方便对照检查自己是不是某一类完全没掌握。组别题号核心考点涉及表关键语法聚合统计1、2、5、6、7、9单值汇总不分组或只出一个数PRODUCT、CUSTOMERCOUNT、SUM、MAX、MIN分组过滤3、4、8按维度分组后再筛组SALE、CUSTOMER、PRODUCTGROUP BY、HAVING连接与嵌套11、12、13、14跨表取数、子查询做条件全部三张表JOIN、IN、EXISTS第一组的共性是“答案是一个数”。这类题的坑在于把本可以直接 WHERE 的题写成了 GROUP BY。第 6 题求库存量超过 500 的产品个数正确答案是一行一个数字写成GROUP BY STOCKS HAVING STOCKS 500之后返回的是每个不同库存值各一行行数完全对不上。第 7 题求单价在 10 到 20 元之间的产品个数同样的毛病GROUP BY PRICE会把单价当成分组维度结果是“每个价位有多少产品”不是“这个区间一共有多少产品”。第二组的共性是“答案是一张按维度排列的小表”。第 3 题按客户汇总订购数量第 4 题按城市数公司第 8 题按产品统计客户数和订购量。这三道题的分组列必须出现在 SELECT 里非分组列要么包在聚合函数里要么就别放。第 8 题原始写法把 OQUANTITY 直接摆在 SELECT 里、GROUP BY 却只有 PCODE这在开启了严格分组检查的数据库上会直接报错在宽松模式下会随机返回组内某一行的值跑十次可能出十个结果。第三组的共性是需要“两层思考”。第 12 题要先知道目标公司在哪个城市再拿这个城市去筛其他公司第 13 题要先知道 A01 的单价再拿这个单价去比第 14 题要先知道哪些产品出现在销售表里再取反。这三道题正好对应子查询的三种典型用法标量比较、集合成员判断、存在性判断。分组分对了练的就不是十四个孤立语法点而是三条可以迁移到实际业务里的思路。3. 统计与分组落地聚合函数、GROUP BY 与 HAVING 的写法边界3.1 聚合函数的四类题型与标准写法聚合函数这块实验里出现的就四个COUNT、SUM、MAX、MIN但每道题的落脚点不同写法上的差别不小。COUNT 关心的是“有多少”SUM 关心的是“加起来多少”MAX 和 MIN 关心的是“极值在哪”它们的共同点是都会把多行压成一行所以一旦 SELECT 里混进了普通列就必须有 GROUP BY 兜底。下面这几条是这一类题里最稳的写法。-- 第 1 题客户总数。COUNT(*) 数行不受任何列空值影响 SELECT COUNT(*) AS customer_cnt FROM CUSTOMER; -- 第 2 题库存总量。SUM 只能作用于数值列 SELECT SUM(STOCKS) AS total_stock FROM PRODUCT; -- 第 5 题所有产品的最高单价 SELECT MAX(PRICE) AS max_price FROM PRODUCT; -- 第 6 题库存量超过 500 的产品个数。 -- 这是行级过滤不是分组过滤用 WHERE 一步到位 SELECT COUNT(*) AS product_cnt FROM PRODUCT WHERE STOCKS 500; -- 第 7 题单价在 10 到 20 元之间的产品个数。 -- BETWEEN 是闭区间含 10 和 20 两个端点 SELECT COUNT(*) AS product_cnt FROM PRODUCT WHERE PRICE BETWEEN 10 AND 20; -- 第 9 题以字母 B 开头的产品的最低单价 SELECT MIN(PRICE) AS min_price FROM PRODUCT WHERE PCODE LIKE B%;逐条说一下取舍。第 1 题用COUNT(*)而不是COUNT(CNO)虽然 CNO 是主键不可能为空、两者结果一样但语义上“数客户”数的是行写成COUNT(*)更直白也避免以后表结构变了出现偏差。第 2 题的SUM(STOCKS)如果表里一行都没有返回的是 NULL 而不是 0这一点在实验报告里写一句会显得你想过边界情况。第 6 题和第 7 题是这一组里最容易写歪的。判断标准很简单题目问的是“产品个数”答案应该是一个标量只要 SELECT 里出现了 COUNT 之外的裸列或者出现了 GROUP BY那基本就是在回答另一个问题。第 6 题如果一定要用分组写正确形式是SELECT COUNT(*) FROM (SELECT PCODE FROM PRODUCT WHERE STOCKS 500) t;但这是绕远路没必要。第 9 题的关键在LIKE B%。百分号匹配任意长度字符包括零个字符所以B本身也会被匹配上。容易出问题的是大小写不同数据库的默认排序规则对字符串比较是否区分大小写不一样某些配置下b01也会被B%命中。想让结果稳定可以写成WHERE UPPER(PCODE) LIKE B%代价是无法用到 PCODE 上的普通索引数据量小的时候完全无所谓。3.2 WHERE 与 HAVING 的分工过滤发生在分组前还是分组后这两者的区别一句话能说清WHERE 在分组之前筛行HAVING 在分组之后筛组。落到具体题目上判断依据是“过滤条件里有没有聚合函数或分组列”。第 4 题求某城市的客户公司数城市是 CUSTOMER 表里的普通列过滤发生在分组前所以该用 WHERE。原始写法用的是GROUP BY SITE HAVING SITE 某市结果是对的但绕了一圈先按城市分成若干组再把不匹配的组扔掉多做了一倍功。更麻烦的是这种写法会让人形成错误直觉遇到“按城市分组、只保留客户数大于 3 的城市”时就分不清哪部分该放 WHERE、哪部分该放 HAVING。-- 第 4 题推荐写法先筛行再分组 SELECT SITE, COUNT(CNO) AS company_cnt FROM CUSTOMER WHERE SITE 某市 GROUP BY SITE; -- 第 3 题按客户汇总订购数量只有分组没有过滤 SELECT CNO, SUM(OQUANTITY) AS total_qty FROM SALE GROUP BY CNO; -- 第 8 题按产品统计分组后再用 HAVING 筛掉不满足条件的组 SELECT PCODE, COUNT(DISTINCT CNO) AS customer_cnt, -- 有多少个不同客户买过 SUM(OQUANTITY) AS total_qty -- 这些客户的订购总量 FROM SALE GROUP BY PCODE HAVING COUNT(DISTINCT CNO) 2 AND MIN(OQUANTITY) 100; -- 每个客户的订购量都超过 100第 8 题的语义值得单独拎出来讲。原题表述是“至少被两个以上客户订购且每个客户订购数量超过 100”这句话本身有歧义可以理解成“总量超过 100”也可以理解成“每一个客户的单笔订购都超过 100”。两种理解写出来的 SQL 不一样前者用SUM(OQUANTITY) 100后者用MIN(OQUANTITY) 100。我在批改的时候更认第二种因为“每个客户订购数量超过 100”里的“每个”是限定到客户这一层的。真到答辩被问到能主动指出这个歧义并给出两种写法比默写一条语句加分得多。COUNT(DISTINCT CNO)里的 DISTINCT 也不能省。虽然当前表结构下同一个客户对同一产品只有一行DISTINCT 加不加结果一样但一旦以后销售表允许拆单同一客户同一产品分多次订购不加 DISTINCT 数出来的就是记录条数而不是客户数。写实验报告时把这一层说明写进去体现的是对数据模型的理解不是对语法的记忆。3.3 分组结果二次筛选容易写歪的两道题第 6、7 题已经在前一节改过了这里补一个更典型的场景如果题目变成“求订购总量超过 500 的客户编号”那就必须走 GROUP BY HAVING因为“订购总量”这个值在原始行上根本不存在是先聚合出来的。这时候写成 WHERE 就必然报错因为 WHERE 执行的时候聚合还没算。-- 分组后再筛聚合结果不能出现在 WHERE 里 SELECT CNO, SUM(OQUANTITY) AS total_qty FROM SALE GROUP BY CNO HAVING SUM(OQUANTITY) 500; -- 对照WHERE 里只能出现原始列 SELECT CNO, SUM(OQUANTITY) AS total_qty FROM SALE WHERE OQUANTITY 100 -- 先筛掉单笔小于等于 100 的行再汇总 GROUP BY CNO;这两段放在一起看执行顺序就清楚了FROM 拿到表WHERE 逐行筛GROUP BY 把剩下的行分组聚合函数在组内计算HAVING 再把不满足条件的组扔掉最后 SELECT 决定输出哪些列。记住这个顺序绝大多数“这条语句该放 WHERE 还是 HAVING”的问题都能自己判断不用死记。还有一个常见的误用是把别名写进 WHERE。SELECT SUM(OQUANTITY) AS total_qty ... WHERE total_qty 500在很多数据库上会直接报“未知列”因为 WHERE 执行时别名还没产生。别名可以用在 ORDER BY 和 HAVING 里部分数据库支持 HAVING 用别名但 WHERE 不行。这类报错信息通常很明确看到“Unknown column”先想是不是别名用错了位置。4. 连接与嵌套从等值连接推进到相关子查询4.1 三表等值连接的写法与字段限定第 11 题是整套实验里第一道真正需要跨表的题要客户编号、产品编号、联系人、订购数量还要限定“某城市客户”和“订购量大于 200”。客户信息在 CUSTOMER订购信息在 SALE两个条件分别落在这两张表上所以至少要连两张表。写法上有隐式连接和显式 JOIN 两种结果一样可读性差别很大。-- 显式 JOIN 写法连接条件和过滤条件分开摆放 SELECT s.CNO, s.PCODE, c.CNAME, s.OQUANTITY FROM SALE s JOIN CUSTOMER c ON c.CNO s.CNO WHERE c.SITE 某市 AND s.OQUANTITY 200; -- 隐式连接写法连接条件混在 WHERE 里和老教材一致 SELECT SALE.CNO, SALE.PCODE, CUSTOMER.CNAME, SALE.OQUANTITY FROM SALE, CUSTOMER WHERE CUSTOMER.CNO SALE.CNO AND CUSTOMER.SITE 某市 AND SALE.OQUANTITY 200;两种写法我都不反对但建议统一用第一种理由是可维护。隐式连接把“表之间怎么关联”和“业务上筛什么”混在一个 WHERE 里两张表还能看清三张表以上就开始数不清哪个条件是连接、哪个条件是过滤漏掉一个连接条件就变成笛卡尔积行数翻几倍还不报错。第 13 题要连 SALE 和 PRODUCT 两张表第 11 题连两张目前还没到三表但把习惯养在两张表的时候成本最低。字段限定符也不能省。SALE 和 CUSTOMER 都有 CNO 列SELECT 里写裸的CNO在某些数据库上会报“列名歧义”即使不报错读代码的人也得猜这个 CNO 来自哪张表。统一写成别名.列名是最省事的做法表别名用单字母s、c、p就够既短又不丢信息。4.2 单行子查询把一个标量值算出来再比较第 12 题和第 13 题是子查询的入门形态内层查询返回一个值外层拿这个值做比较。第 13 题要找“单价比 A01 高的产品的订购记录”思路分两步先查出 A01 的单价再拿这个单价去筛 SALE 和 PRODUCT 的连接结果。-- 第 13 题内层返回单个单价外层做 比较 SELECT s.PCODE, s.CNO, s.OQUANTITY FROM SALE s JOIN PRODUCT p ON p.PCODE s.PCODE WHERE p.PRICE ( SELECT PRICE FROM PRODUCT WHERE PCODE A01 );这段能跑通的前提是内层最多返回一行也就是 PCODE 是 PRODUCT 的主键。主键唯一性保证了这一点所以用是安全的。反过来说如果内层查的是一个可能返回多行的列比如按名称查、名称没加唯一约束这条语句就会在某些数据库上直接抛“子查询返回多于一行”的错误在另一些数据库上悄悄取第一行。这个差异很坑因为本地跑得好好的换台机器就报错。第 12 题的结构相同但坑更深一层要找“和目标公司在同一城市的其他公司”。内层按公司名查城市外层按城市查公司。如果同一城市只有一家叫这个名字的公司内层返回一行能用一旦数据里出现重名立刻炸。-- 第 12 题稳妥写法用 IN 兜住内层多行的情况 SELECT CNAME, TELE FROM CUSTOMER WHERE SITE IN ( SELECT SITE FROM CUSTOMER WHERE CNAME 某公司 ) AND CNAME 某公司; -- 排除目标公司自身这里有两个细节。一是把换成IN语义上等价于“城市属于内层返回的城市集合”内层返回一行还是多行都不会报错。二是补了CNAME 某公司因为“与某公司同城的客户公司”按常规理解不包含它自己。原题没明说要不要排除自身但答辩时被问到“为什么结果里有目标公司”答不上来就很尴尬。主动排除并在报告里写一句是加分项。4.3 多行子查询与 EXISTS第 14 题的稳妥写法第 14 题求“没有被订购的产品编号和名称”本质是一个差集运算PRODUCT 里减去 SALE 里出现过的产品。原写法是WHERE PRODUCT.PCODE ! (SELECT SALE.PCODE FROM SALE)这条语句有两个独立的毛病随便踩中一个结果就是错的。第一个是内层会返回多行!后面跟多行在多数数据库上直接报错第二个是即使数据库容忍了!配子查询做的是“不等于其中某一个”的判断逻辑上根本不是差集。-- 第 14 题推荐写法一NOT EXISTS相关子查询 SELECT p.PCODE, p.PNAME FROM PRODUCT p WHERE NOT EXISTS ( SELECT 1 FROM SALE s WHERE s.PCODE p.PCODE ); -- 第 14 题推荐写法二NOT IN注意 NULL 风险 SELECT PCODE, PNAME FROM PRODUCT WHERE PCODE NOT IN ( SELECT PCODE FROM SALE WHERE PCODE IS NOT NULL );NOT EXISTS是这类“取反”题里最稳的。它逐行拿 PRODUCT 的 PCODE 去 SALE 里试找不到就保留语义直白而且不受 NULL 影响——因为 EXISTS 只关心“有没有行”不关心行里的值是什么。NOT IN写法更短但必须确认子查询结果里没有 NULL否则整个条件会变成 UNKNOWN一行都返回不了。当前 SALE.PCODE 是主键的一部分不可能为空所以两种写法等价但把IS NOT NULL写上不亏是给自己留的保险。还有第三种写法用 LEFT JOIN 找右表为空的记录-- 第 14 题推荐写法三左连接后筛右表为空 SELECT p.PCODE, p.PNAME FROM PRODUCT p LEFT JOIN SALE s ON s.PCODE p.PCODE WHERE s.PCODE IS NULL;三种写法结果一致执行计划在不同数据量下各有优劣但在这个实验的数据规模上感觉不出来。我通常让学生至少写两种并说明为什么等价这样答辩时不管被问到哪种都能接住。真要选一个作为默认写法NOT EXISTS的语义最贴近题目表述“没有被订购的产品”就是“不存在一条订购记录的”。5. 避坑与排查五个让结果对不上的高频问题5.1 现象GROUP BY 之后结果随机变重跑一次数不同原因基本可以锁定在 SELECT 里混了非分组列。第 8 题的原始写法把 OQUANTITY 摆在 SELECT 里、GROUP BY 只有 PCODE一个产品被多个客户订购时组内有多行 OQUANTITY数据库要么直接报错要么随便挑一行返回。后者更危险因为它不报错你会以为语句没问题。排查方法是把 SELECT 里的裸列逐个检查一遍这一列要么出现在 GROUP BY 里要么被聚合函数包住二者必居其一。解决思路是先想清楚“我要的是每个产品一行那这一行里的订购数量代表什么”如果代表总量就用 SUM代表最大值就用 MAX代表某一个具体客户的量那就说明分组维度选错了应该按“产品 客户”分组。-- 反例OQUANTITY 既不在 GROUP BY 里也不在聚合函数里 SELECT PCODE, OQUANTITY FROM SALE GROUP BY PCODE; -- 正例把非分组列包进聚合函数或加进分组维度 SELECT PCODE, SUM(OQUANTITY) AS total_qty FROM SALE GROUP BY PCODE;5.2 现象明明有数据加了条件之后一行都不返回先在脑子里过一遍这个条件里有没有 NULL 参与比较。三值逻辑里任何值和 NULL 做、!、比较结果都是 UNKNOWN而 WHERE 只保留结果为 TRUE 的行。最典型的翻车点是NOT IN配上一个可能含 NULL 的子查询内层结果里只要有一个 NULL整个NOT IN就永远不成立返回空集且不报任何错。排查办法是先把子查询单独跑一遍看结果里有没有 NULL。SELECT PCODE FROM SALE WHERE PCODE IS NULL;一条语句就能确认。如果确实有要么在子查询里加WHERE PCODE IS NOT NULL要么整体换成NOT EXISTS。第 14 题就属于这一类虽然当前表结构下 PCODE 不会为空但换个数据源、换个可空列同样的写法立刻失效。5.3 现象或!接子查询时报“返回多于一行”这属于把单行子查询的假设用在了多行场景上。第 12 题按公司名查城市、第 14 题按产品查订购记录内层返回几行完全取决于数据。主键或唯一约束能保证单行其他列不能。开发阶段数据少恰好只有一行测试全绿换成完整数据集就报错这类问题最耗时间。解决办法分两种。如果业务上确实只会有一个值比如按主键查那就在子查询里加LIMIT 1并接受“取第一条”的语义但更推荐的做法是保留约束本身、别依赖 LIMIT 掩盖数据问题。如果业务上可能有多个值直接换成IN或EXISTS把“等于某一个”改成“属于某个集合”或“存在匹配行”语义和稳定性都更好。5.4 现象连接两张表之后统计数字翻了好几倍这是笛卡尔积的典型症状。两表连接时漏写连接条件或者连接条件写得不够严比如用了一个不唯一的列做等值结果集行数会变成两表行数的乘积。第 11 题里 SALE 和 CUSTOMER 靠 CNO 关联如果 WHERE 里只写了城市条件和数量条件、忘了CUSTOMER.CNO SALE.CNO一个客户有多少条订购记录就会被重复匹配客户表的行数倍。排查时先单独跑SELECT COUNT(*) FROM 表A;和SELECT COUNT(*) FROM 表B;再跑连接后的行数如果接近两者乘积基本可以确定漏了条件。解决就是补上等值连接条件并且养成用显式 JOIN 的习惯——ON后面写连接条件、WHERE后面写过滤条件物理上分开漏写的概率会低很多。5.5 现象LIKE 查出来的结果比预期多或少LIKE B%这类模式匹配问题通常出在排序规则和通配符理解上。百分号匹配任意长度字符串含零长度下划线匹配恰好一个字符这两个容易混。另外某些数据库的默认排序规则下字符串比较不区分大小写B%会把b01也捞进来反过来如果列上建了普通索引用UPPER(PCODE) LIKE B%虽然结果稳定但索引可能用不上。第 9 题只要求最低单价多匹配几行可能不影响结果最小值往往不变但换成“统计以 B 开头的产品个数”就会直接错。解决办法是先跑SELECT PCODE FROM PRODUCT WHERE PCODE LIKE B%;看实际命中哪些确认大小写和边界需要严格控制时显式写WHERE PCODE LIKE BINARY B%或WHERE PCODE REGEXP ^B具体语法按手头数据库的文档来别跨库照搬。6. 验收与答辩用一张结果对照表把十四道题跑通这套实验的验收核心不是“语句能不能执行”而是“结果能不能解释”。我一般要求做完之后交一张对照表每道题写清三件事这条语句返回几行、每行代表什么业务含义、换一组数据会不会失效。把这张表填满基本就等于把十四道题的逻辑都过了一遍脑子。题号预期返回形态关键验证点易错写法1、2、5单行单列聚合结果是否为空用 COUNT(列) 代替 COUNT(*)6、7、9单行单列WHERE 是否在分组前生效误加 GROUP BY 变成多行3、4多行每行一个维度分组列是否都在 SELECT 里用 HAVING 代替 WHERE8多行每行一个产品每个客户订购量都超 100非分组列裸露在 SELECT11多行跨两表字段连接条件是否完整漏写等值条件出笛卡尔积12多行不含目标公司自身内层是否可能多行用 接多行子查询13多行单价严格大于内层是否唯一比较方向写反14多行SALE 中不存在的产品子查询是否有 NULL用 ! 接多行子查询验收时的具体动作我习惯按这个顺序走一遍。先把三张表的行数各查一次并记下来这是后面所有计数的基准。再按题号顺序逐条执行每执行一条就把结果行数和对照表里的预期形态比一次行数不对立刻停下来查不要往下跑。全部跑完后挑三道题做“改数据验证”往 SALE 里插一条新记录看第 3、8、14 题的结果是否按预期变化变化方向不对说明语句里藏着硬编码或者逻辑漏洞。答辩环节通常集中在几个点上。第一个高频问题是“为什么这条用 HAVING 不用 WHERE”答的时候不要背定义直接说这条语句里过滤条件用到了聚合结果聚合在分组之后才算出来所以只能放 HAVING。第二个是“子查询能不能改成连接”答案是可以很多场景下连接的可读性和执行效率更好但要说明改写后如何去重——子查询天然去重连接不一定这个差异经常被忽略。第三个是“如果销售表允许同一客户同一产品多条记录你的语句还对不对”这道题最能区分背语句和真理解的人凡是用了 COUNT(PCODE) 而没加 DISTINCT 的这里都会露馅。还有一个容易被忽视的准备动作把自己的语句在两种不同规模的数据上各跑一遍。小数据量下很多错误不显现比如漏写连接条件两表各三行时笛卡尔积才九行看着像正常结果换成各一百行就是一万行一眼就能看出不对。我一般会临时复制一份表插几十行造出来的数据进去跑专门用来暴露这类问题。说个我自己踩过的坑。早年做类似的查询练习第 14 题我用NOT IN写得飞快本地数据全是干净的一路绿灯换了一套带空值的数据之后结果直接变成零行我盯着屏幕找了四十分钟最后把子查询单独跑出来才发现里面有一行 NULL。从那以后我每次写取反类查询都会强制先跑一遍子查询看有没有空值有就换NOT EXISTS没有也顺手加个IS NOT NULL保底。这个习惯后来帮我省下的时间远超当初多写那几个字符的成本。希望这套按考点重排的思路和这张验收表能帮你把这份实验五跑得顺一点。本文还有配套的精品资源点击获取
RELATED

相关推荐

CPXS数据库实验:统计查询、分组过滤与嵌套子查询四层方案

CPXS数据库实验:统计查询、分组过滤与嵌套子查询四层方案

简介:《数据库实验5嵌套查询》是一份面向数据库课程学习者与实验课教师的实验报告文档,围绕 SELECT 统计查询、常用统计函数、连接查询与嵌套查询展开,帮助读者理解多表检索、子查询、派生表及相关谓词的使用场景。文档以 CPXS 数据库为操作对…

📅 2026/10/31 18:14:11
SQL嵌套查询入门:SELECT、子查询、连接查询与报错排查

SQL嵌套查询入门:SELECT、子查询、连接查询与报错排查

简介:面向数据库课程学习者与实验教学场景的《数据库实验5嵌套查询》实验报告文档,聚焦SELECT统计查询、聚合函数与嵌套查询的实操训练,适合课后复盘、实验提交和语法查漏补缺,并配有实验目的、内容与思考模块。压缩包内共1个doc文…

📅 2026/10/31 18:14:11
数据库实验5嵌套查询:统计函数、连接查询与子查询避坑指南

数据库实验5嵌套查询:统计函数、连接查询与子查询避坑指南

简介:这份文档面向数据库课程学习者,聚焦数据统计查询与嵌套查询的实验训练,可用于高校数据库原理课程实验复盘、SQL语句对照练习和查询思路梳理。内容围绕CPXS数据库展开,先交代掌握SELECT统计查询、COUNT/SUM/MAX/MIN等主要函数…

📅 2026/10/31 18:14:11
MORE NEWS

更多资讯

📰

数据安全治理:从业务语义驱动的动态决策系统

简介:《数据安全治理白皮书5.0》是由中关村网络安全与信息化产业联盟数据安全治理专业委员会权威发布的行业标杆报告,面向政企数据安全管理者、合规负责人、安全架构师及数字化转型决策者,系统回应数字经济下数据泄露、滥用、跨域流通失序等核…

📰

参数调优找平衡点:二分法、三分法与黄金分割工程实践

在参数调优、阈值定标这类活里,最耗时间的往往不是写代码,而是反复问自己一个问题:这个值到底取多少才合适。取小了效果不够,取大了成本翻倍,中间那条"刚刚好"的线,我们平时就叫它平衡点。找平衡…

📰

二分法与牛顿迭代法:平衡点求根的工程实践与避坑指南

做仿真、做标定、做成本测算的人都碰到过同一个动作:找那个让两端刚好抵消的位置。机械臂配重调到某个质量正好不偏,产品产量到某个数字刚好不亏,控制回路里某个参数让偏差归零,这些说的都是寻找平衡点。手上有两个趁手的办法最常…

📰

收藏夹里的良心网站为何总失效?71个名额的筛选与维护策略

收藏夹里躺着两百多个链接,这是我这几年看各种"良心网站合集"攒下来的家底。上个月我心血来潮做了一次大扫除,点开前五十个,能正常打开的不到一半,剩下的要么跳转到某个毫不相关的页面,要么干脆给你一个打不…

📰

OpenAI暂停训练背后:智能体失控风险与AI安全落地指南

2026年9月28日,AI圈被一条消息炸开了锅:OpenAI暂停了当前最强模型的训练。同一时间,热搜榜上“智能体失控”这个词条也挂了大半天。一个是全球头部AI实验室,一个是已经被反复讨论过多次的工程问题,放在同一天出现&…

📰

Strands Harness SDK:一行代码启动生产级Agent服务

1. 项目概述:为什么“一行代码”能终结手写 Agent 循环的苦役?Strands Agents Harness SDK 这个名字乍看像一串技术黑话拼贴——Strands(丝线)、Agents(智能体)、Harness(挽具/驾驭装置&#xf…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬