【数据库04】中级开发需要掌握哪些SQL进阶玩法 1

简介: 【数据库04】中级开发需要掌握哪些SQL进阶玩法

1.连接表达式

前一篇文章我们使用笛卡尔积运算符来组合来自多个关系的信息,本文介绍“连接”查询,允许程序员以一种更自然的方式编写一些查询,并表达只用笛卡尔积很难表达的查询。

本节所用的示例设计studenttakes两个关系,如下图所示。请注意对于ID为98988的学生,在2018年夏季选修的BIO-301课程的1号课程段的grade属性为空值,该空值表示它尚未得到成绩。

d3d0aee503e34a7db89906a8077168a0.jpg

1.1 自然连接

请考虑以下SQL查询,该查询为每名学生计算该学生已经选修的课程的集合。

select name,curse_id
from student,takes
where student.ID = takes.ID;


请注意,此查询仅输出已选修某些课程的学生,未选修任何课程的学生不会被输出。请注意上面连接条件中student.IDtakes.ID具有相同的属性名ID,这在实际的SQL查询中含常见,自然连接被设计出来简化上述情况的查询。

自然连接运算作用于两个关系,并产生一个关系作为结果。与两个关系的笛卡尔积不同,自然连接只考虑在两个关系的模式中都出现的那些属性上取值相同的元组对,而笛卡尔积将第一个关系的每个元组与第二个关系的每个元组进行串接。

上面的SQL也可以这么写。

student natural join takes

其查询结果如下,注意属性的列出顺序,受限是两个关系模式中的公共属性,其次是第一个关系模式中的那些属性,最后是只出现在


f7f3debfd56f4c2a8f46d5c76c4817d9.jpg

第二个关系中的那些属性。

之前有一个查询,"对于大学中已经选课的所有学生,找出他们的姓名以及他们选修的所有课程的标识。”我们可以这么写。

select name, course_id
from student natural join takes;

在一条SQL查询的from字句中,可以用自然连接把多个关系结合在一起。

select A1,A2....An
from r1 natural join r2 natural join r3... natural join rm
where P;

更一般地,from子句可以写为如下形式。

from E1,E2...En

每个Ei可以是单个关系或者一个涉及自然连接的表达式。例如,假设我们要查询“列出学生的姓名和他们所选择的课程的名称”。可以写。

select name,title
from student natural join takes, course
where takes.course_id = course.course_id;

受限计算studnet和takes的自然连接,再计算该结果与course的笛卡尔积,where字句从结果中再过滤,过滤条件是course_id相匹配。

思考如下sql与上面的sql是否会等价。

select name,title
from student natural join takes natural join course

不是!!!


请注意student和takes做自然连接后包含的属性是(ID,name,dept_name,tot_cred,course_id,sec_id),而course包含的属性是(course_id,titile,dept_name,credits)。上面二者做自然连接,不仅需要course_id取值相同,还需要dept_name取值相同。

为了避免这样的错误出现,我们可以这样做。

select name,title
from (student natural join takes) join course using (course_id);

1.2 连接条件

除了上面的join using外,还可以使用on关键字指定连接条件。

select * 
from student join takes on student.ID = takes.ID;

这与自然查询的结构是一样的,唯一的区别在于查询结果ID出现两次,一次是student中的,一次是takes结果中的。如果希望ID只出现一次,可以这么做。

select student.ID as ID,name,dept_name,tot_cred,
  course_id,sec_id,semester,year,grade
from student join takes on student.ID = takes.ID; 

爱思考的读者会发现,on关键字似乎可以被where所替代,那它是不是一个冗余的语法?实际上,on关键字在外连接中与where表现是不同的,其次,如果使用on作为连接条件,并在where字句中出现其余的条件,sql查询会更加清晰易懂。

1.3 外连接

假设我们希望查询所有学生的个人信息与选修的课程,可能会想到如下检索。

select * from student natural join takes

不过如果一个学生没有选修课程,就不会出现在这个结果中。

我们可以改用外连接来实现我们的需求。外连接与我们已经学习过的连接运算类似,但是它会通过在结果中创建包含空值的元组,来保留那些在连接中会丢失的元组。

外连接分为三种,

  • 左外连接。只保留连接关键字之前的关系的元组。
  • 右外连接。只保留连接关键字之后的关系的元组。
  • 全外连接。保留出现在两个关系中的元组。
  • 相比较而言,我们之前学习的不保留未匹配元组的连接运算被称为内连接运算。

比如"查询所有学生的个人信息与选修的课程"可以这样用左外连接实现。

select * 
from student natural left outer join takes;

查询“一门课程也没有选修的学生”。

select ID
from student  natural left outer join takes
where course_id is null;

左外连接与右外连接是对称的,用右外连接实现"查询所有学生的个人信息与选修的课程"。

select * 
from take natural right outer join student ;

全外连接可以看做左外连接与右外连接的并运算。考虑查询,“显示Comp.Sci系中所有学生以及他们在2017年春季选修的所有课程段的列表。在2017年春季选修的所有课程段都必须显示。”

select *
from (select * 
  from student
  where dept_name = 'Comp.Sci')
  natural full outer join
  (select *
  from takes
  where semester = 'Spring' and year = 2017);

在外连接中,where和on关键字表现是不同的。on会作为外连接声明的一部分,而where却不是。使用where时不会补全具有空值的元组,使用on则会。

另外,常规连接也被称为内连接,可以使用缺省的关键字inner

2.视图

让所有用户看到数据库关系中的完整集合并不合适,我们可以通过SQL授权来限制对关系的访问,但是如果仅需要向用户隐藏一个关系中的特定数据,可以使用视图。

除了安全型的考虑,视图还可以通过定制化更好的匹配特定用户的需求。

2.1 视图定义

创建视图语法是。

create view v as <查询表达式>;

考虑需要访问instrutor除了salary外的所有数据的职员。

create view faculty as
  select ID,name,dept_name
  from instructor;

视图在概念上包含查询结果中的元组,但是不进行预计算和存储。我通俗的理解成,创建视图是创建了一个规则,使用视图时再根据规则进行计算。

2.2 在SQL查询中使用视图

创建视图后可以像使用数据表一样使用视图。如。

select ID from faculty ;

可以显示的指定视图的属性名称。

create view department_total_salary(dept_name, total_salary) as
  select dept_name,sum(salary)
  from instructor
  group by dept_name;

直观的说,任意给定时刻,视图关系几种的元组集都是使用定义视图查询表达式求值的结果,因此如果定义并存储一个视图关系,一旦定义视图的关系被修改,那么视图就会过期。

一个视图还可以被用到另一个视图的定义中去。

2.3 物化视图

某些数据库系统中的视图关系保证:如果定义视图的实际关系发生改变,则视图也跟着修改以保持更新,这样的视图被称为物化视图。如果视图是物化的,则其计算结果会被存储在计算机中,从而在使用视图时可以更快的运行。

既然物化视图会预计算并存储,那么就需要保持物化视图的更新,保持物化视图一直在最新的状态的过程被称为物化视图维护,或者视图维护。这种维护策略可以是实时维护,周期维护,惰性维护(被使用时才更新),人工维护等,支持的策略与数据库产品有关。

物化视图对于频繁使用的视图有帮助,对大型关系的聚集运算也较为适用,需要平衡其存储代价与性能开销。

2.4 视图更新

对视图进行增删改可能会带来严重的问题,因为用视图表达的修改必须被翻译为对数据库关系的实际修改。一般不允许对视图进行更新。不同的数据库可能会指定不同的条件,在满足这些条件的前提下可以对视图进行更新,具体可以参考其系统手册。

一般说来,如果定义视图的查询满足下面条件,那么称SQL视图是可更新的

  • from字句中只有一个数据库关系
  • select子句中只包含关系的属性名,并不包含任何的表达式、聚集或者distinct声明。
  • 没有出现在select子句中的任何属性都可以取null值。也就是说,这些属性没有非空约束,也不构成主码的一部分。
  • 查询中不包含有group by或者having子句。
  • 不过要注意,即使满足上面的限制条件,仍然不一定可以将数据顺利插入视图。定义如下视图。
create view history_instructors as
select *
from instructor
where dept_name = 'History';

考虑如下查询。尝试向history_instructors视图中插入元组(‘25566’,‘Brown’,‘Biology’,10000)。这个元组可以被插入instructor关系中,但是不满足视图的选择要求dept_name = 'History'。他不应该出现在视图history_instructors中。

我们可以在视图定义的末尾添加with check option子句做到这一点,如果新值满足where子句的条件,就可以插入视图,否则,数据库系统会拒绝该插入操作。

SQL:1999对于视图有更加复杂的规则集。这里不讨论。

触发器机制提供了另外一种视图修改数据库的机制,它更加可取,后续文章将详细介绍。

相关文章
|
9天前
|
SQL 存储 数据管理
SQL Server数据库
SQL Server数据库
22 11
|
4天前
|
SQL 监控 关系型数据库
MySQL数据库中如何检查一条SQL语句是否被回滚
检查MySQL中的SQL语句是否被回滚需要综合使用日志分析、事务状态监控和事务控制语句。理解和应用这些工具和命令,可以有效地管理和验证数据库事务的执行情况,确保数据的一致性和系统的稳定性。此外,熟悉事务的ACID属性和正确设置事务隔离级别对于预防数据问题和解决事务冲突同样重要。
17 2
|
12天前
|
SQL 分布式计算 大数据
大数据开发SQL代码编码原则和规范
这段SQL编码原则强调代码的功能完整性、清晰度、执行效率及可读性,通过统一关键词大小写、缩进量以及禁止使用模糊操作如select *等手段提升代码质量。此外,SQL编码规范还详细规定了代码头部信息、字段与子句排列、运算符前后间隔、CASE语句编写、查询嵌套、表别名定义以及SQL注释的具体要求,确保代码的一致性和维护性。
17 0
|
16天前
|
SQL 安全 数据库
基于SQL Server事务日志的数据库恢复技术及实战代码详解
基于事务日志的数据库恢复技术是SQL Server中一个非常强大的功能,它能够帮助数据库管理员在数据丢失或损坏的情况下,有效地恢复数据。通过定期备份数据库和事务日志,并在需要时按照正确的步骤恢复,可以最大限度地减少数据丢失的风险。需要注意的是,恢复数据是一个需要谨慎操作的过程,建议在执行恢复操作之前,详细了解相关的操作步骤和注意事项,以确保数据的安全和完整。
36 0
|
20天前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
35 0
|
20天前
|
SQL 数据处理 数据库
|
20天前
|
SQL 存储 调度
|
3天前
|
NoSQL 关系型数据库 MySQL
微服务架构下的数据库选择:MySQL、PostgreSQL 还是 NoSQL?
在微服务架构中,数据库的选择至关重要。不同类型的数据库适用于不同的需求和场景。在本文章中,我们将深入探讨传统的关系型数据库(如 MySQL 和 PostgreSQL)与现代 NoSQL 数据库的优劣势,并分析在微服务架构下的最佳实践。
|
5天前
|
存储 SQL 关系型数据库
使用MySQL Workbench进行数据库备份
【9月更文挑战第13天】以下是使用MySQL Workbench进行数据库备份的步骤:启动软件后,通过“Database”菜单中的“管理连接”选项配置并选择要备份的数据库。随后,选择“数据导出”,确认导出的数据库及格式(推荐SQL格式),设置存储路径,点击“开始导出”。完成后,可在指定路径找到备份文件,建议定期备份并存储于安全位置。
65 11
|
24天前
|
弹性计算 关系型数据库 数据库
手把手带你从自建 MySQL 迁移到云数据库,一步就能脱胎换骨
阿里云瑶池数据库来开课啦!自建数据库迁移至云数据库 RDS原来只要一步操作就能搞定!点击阅读原文完成实验就可获得一本日历哦~