当前位置: 首页 > news >正文

3.4 《数据库系统概论》之数据查询---SELECT(从基础到进阶:单表操作、多表关联与子查询实战)

1. SELECT查询基础入门

SQL查询就像在图书馆找书一样,SELECT语句就是我们的"图书检索系统"。想象一下,当你走进图书馆,首先要确定想找什么书(选择列),在哪个区域找(从哪张表),以及有什么具体要求(过滤条件)。这就是SELECT查询的基本逻辑。

SELECT语句的标准格式如下:

SELECT [ALL|DISTINCT] <目标列表达式> [别名] FROM <表名或视图名> [别名] [WHERE <条件表达式>] [GROUP BY <列名1> [HAVING <条件表达式>]] [ORDER BY <列名2> [ASC|DESC]]

举个最简单的例子,假设我们有一个学生表Student,包含学号(Sno)、姓名(Sname)、年龄(Sage)等字段:

-- 查询所有学生的姓名和年龄 SELECT Sname, Sage FROM Student; -- 查询计算机系的所有学生信息 SELECT * FROM Student WHERE Sdept = 'CS';

在实际项目中,我经常看到新手容易犯的几个错误:

  1. 忘记指定WHERE条件导致全表扫描
  2. SELECT * 查询不必要的数据列
  3. 忽略DISTINCT导致结果重复

2. 单表查询的进阶技巧

2.1 列选择与计算字段

SELECT不仅可以查询原始列,还能进行各种计算和转换:

-- 计算学生出生年份(假设当前是2023年) SELECT Sname, 2023-Sage AS BirthYear FROM Student; -- 使用函数处理数据 SELECT Sname, UPPER(Sdept) AS Department FROM Student; -- 使用CASE WHEN条件表达式 SELECT Sname, CASE WHEN Sage < 20 THEN '新生' ELSE '老生' END AS StudentType FROM Student;

2.2 条件过滤的艺术

WHERE子句是SQL的过滤系统,常用的条件运算符包括:

  • 比较运算符:=, >, <, >=, <=, <>
  • 范围检查:BETWEEN AND
  • 集合检查:IN
  • 模糊匹配:LIKE
  • 空值判断:IS NULL
-- 查询年龄在20-23岁之间的学生 SELECT * FROM Student WHERE Sage BETWEEN 20 AND 23; -- 查询姓"张"且名字为两个字的学生 SELECT * FROM Student WHERE Sname LIKE '张_'; -- 查询没有成绩记录的选课信息 SELECT * FROM SC WHERE Grade IS NULL;

2.3 排序与聚合函数

ORDER BY和聚合函数是数据分析的利器:

-- 按成绩降序排列 SELECT Sno, Grade FROM SC WHERE Cno='3' ORDER BY Grade DESC; -- 常用聚合函数 SELECT COUNT(*) AS TotalStudents, AVG(Sage) AS AvgAge, MAX(Sage) AS MaxAge FROM Student;

GROUP BY的使用需要注意:

  1. SELECT中的非聚合列必须出现在GROUP BY中
  2. WHERE在分组前过滤,HAVING在分组后过滤
-- 统计各系学生人数 SELECT Sdept, COUNT(*) AS StudentCount FROM Student GROUP BY Sdept; -- 查询选课超过3门的学生 SELECT Sno, COUNT(*) AS CourseCount FROM SC GROUP BY Sno HAVING COUNT(*) > 3;

3. 多表连接查询实战

3.1 连接原理与类型

连接查询就像拼图游戏,我们需要找到表之间的关联字段。常见的连接类型包括:

  1. 内连接(INNER JOIN):只返回匹配的行
  2. 左外连接(LEFT JOIN):返回左表所有行,右表不匹配则为NULL
  3. 右外连接(RIGHT JOIN):返回右表所有行,左表不匹配则为NULL
  4. 全外连接(FULL JOIN):返回左右表所有行
-- 等值连接:查询学生及其选课信息 SELECT Student.Sno, Sname, Cno, Grade FROM Student, SC WHERE Student.Sno = SC.Sno; -- 使用JOIN语法更清晰 SELECT Student.Sno, Sname, Cno, Grade FROM Student INNER JOIN SC ON Student.Sno = SC.Sno;

3.2 连接性能优化

多表连接时,数据库通常采用以下算法:

  1. 嵌套循环连接(Nested Loop):适合小表驱动大表
  2. 哈希连接(Hash Join):适合中等规模数据
  3. 排序合并连接(Sort-Merge):适合已排序数据
-- 复合条件连接:查询选修2号课程且成绩>88的学生 SELECT Student.Sno, Sname FROM Student JOIN SC ON Student.Sno = SC.Sno WHERE SC.Cno='2' AND SC.Grade > 88;

在实际项目中,连接查询最容易出现的性能问题就是笛卡尔积(忘记写连接条件),我曾见过一个查询因为漏写连接条件,导致两个百万级表的笛卡尔积,直接把数据库卡死。

4. 子查询与嵌套查询

4.1 子查询类型

子查询就像SQL中的"俄罗斯套娃",主要分为:

  1. 不相关子查询:子查询可独立执行
  2. 相关子查询:子查询依赖外部查询
-- 不相关子查询:查询与"刘晨"同系的学生 SELECT Sno, Sname, Sdept FROM Student WHERE Sdept IN (SELECT Sdept FROM Student WHERE Sname='刘晨'); -- 相关子查询:查询超过自己平均成绩的课程 SELECT Sno, Cno FROM SC x WHERE Grade >= (SELECT AVG(Grade) FROM SC y WHERE y.Sno=x.Sno);

4.2 EXISTS与NOT EXISTS

EXISTS用于检查子查询是否返回结果,不关心具体数据:

-- 查询选修了1号课程的学生 SELECT Sname FROM Student WHERE EXISTS (SELECT * FROM SC WHERE Sno=Student.Sno AND Cno='1');

4.3 集合查询

集合操作包括UNION(并)、INTERSECT(交)、EXCEPT(差):

-- 查询计算机系或年龄<19的学生 SELECT * FROM Student WHERE Sdept='CS' UNION SELECT * FROM Student WHERE Sage<19;

5. 实战案例与性能优化

5.1 典型查询模式

-- 查询每个学生的总学分 SELECT Student.Sno, Sname, SUM(Ccredit) AS TotalCredit FROM Student JOIN SC ON Student.Sno = SC.Sno JOIN Course ON SC.Cno = Course.Cno WHERE Grade >= 60 -- 及格才算学分 GROUP BY Student.Sno, Sname; -- 查询各科成绩前三名 SELECT Cno, Sno, Grade FROM SC x WHERE (SELECT COUNT(*) FROM SC y WHERE y.Cno=x.Cno AND y.Grade>x.Grade) < 3 ORDER BY Cno, Grade DESC;

5.2 性能优化建议

  1. 为常用连接字段创建索引
  2. 避免在WHERE条件中对字段进行函数操作
  3. 只查询需要的列,避免SELECT *
  4. 大数据量表连接时,先过滤再连接
  5. 复杂查询考虑使用临时表或视图
-- 优化示例:先过滤再连接 SELECT S.Sno, Sname, Cname, Grade FROM (SELECT * FROM Student WHERE Sdept='CS') S JOIN SC ON S.Sno = SC.Sno JOIN Course ON SC.Cno = Course.Cno;

在实际项目中,我曾优化过一个需要20秒执行的查询,通过添加适当的索引和重写查询逻辑,最终将执行时间降到了0.5秒。关键是要理解数据库的执行计划,知道它如何访问和处理数据。

http://www.jsqmd.com/news/1186604/

相关文章:

  • 告别模组管理噩梦:XXMI启动器如何让多游戏模组体验变得简单有趣
  • RimSort模组管理器:5步解决《环世界》模组加载难题
  • 3步解锁网易云音乐NCM格式:ncmdumpGUI让加密音乐重获自由
  • ZYNQ7000学习笔记(3)——深入剖析PS与PL的AXI互联架构
  • HybridCLR热更在微信小游戏报错:IL2CPP完全泛型共享优化问题解析与解决方案
  • 抖音直播间数据抓取实战:5步构建你的实时监控系统
  • M2.1代码语义分析:专治Java祖传屎山的工程级重构方案
  • 工业传感器控制系统:AD74115H与PIC18F86J15实战解析
  • TB67H480FNG与STM32F303VE电机控制方案详解
  • ManiSkill实战:如何为GPU加速机器人仿真平台自定义专属机器人
  • OpenViking 上下文数据库 | 11 - Vikingbot:把上下文数据库做成可聊天的 Agent
  • 零基础如何免费自学计算机科学?OSSU完整指南助你2年掌握核心技能
  • ConfettiSwiftUI进阶实战:从圆角六角形到动态曼陀罗的创意路径绘制
  • STM32 低功耗实战:模式选择、唤醒策略与电源优化
  • Facepunch.Steamworks:C开发者的Steamworks集成终极解决方案
  • 上海取保候审律师哪家客户评价最好:多平台口碑交叉验证方法 - 品牌深度评测
  • Warp终端主题定制:打造你的专属开发美学空间
  • 《数据库系统概论》实战:从零到一构建电商订单系统的六步设计法
  • Unity2022微信小游戏真机黑屏问题:根源剖析与系统解决方案
  • 突破性真实感增强:FLUX专用LoRA插件深度实战指南
  • Unity开发Hololens2—从零到一:避开官方文档的坑,实现高效部署
  • AMD显卡Vulkan后端深度解析:llama.cpp完整兼容方案实战指南
  • 浪琴中国大陆官方售后服务网点|官网认证地址及电话全新启用(2026年 7月最新) - 浪琴中国服务中心
  • C++ string核心原理与高效编程实战:从内存模型到SSO优化
  • 2026实验室净化空调靠谱商家实测排名,避坑选购攻略大全 - myqiye
  • ChatGPT+Excel+Python三合一数据分析法:7步实现从原始数据到商业洞察的自动化闭环
  • 设计模式到底在“守“什么原则?用代码把六大原则“钉“在每一行上
  • C++构建高并发社区健康管理系统:架构设计、数据库优化与实战经验
  • NHSE终极指南:免费开源动森存档编辑器,打造你的梦想岛屿
  • 3步快速上手Indico:如何高效管理学术会议与活动?