SQL学习指南第三篇
再谈连接
外连接
之前的范例都是没有考虑条件可能无法为表中的所有行匹配的问题
左外连接与右外连接
SELECT a.account_id, a.cust_id, b.name FROM account a LEFT OUTER JOIN business b ON a.cust_id = b.cust_id;
外连接包括第一个表的所有行,但仅仅包含第二个表中那些匹配行的数据。关键字 left 指出连接左边的表决定结果集的行数,而右边只负责提供与之匹配的列值。因此,如果想要通过表 A 和 B 外连接得到结果为 A 中的所有行和 B 中匹配列的额外数据,则可以指定 A left outer join B 或者 B right outer join A。
三路外连接
SELECT a.account_id, a.product_cd, CONCAT(i.fname, ' ', i.lname) AS person_name, b.name AS business_name
FROM account a LEFT OUTER JOIN individual i ON a.cust_id = i.cust_id
LEFT OUTER JOIN business b ON a.cust_id = b.cust_id;
--利用子查询限制查询中连接的数目
SELECT account_ind.account_id, account_ind.product_cd, account_ind.person_name, b.name AS business_name FROM
(SELECT a.account_id, a.product_cd, a.cust_id, CONCAT(i.fname, ' ', i.lname) AS person_name FROM account a
LEFT OUTER JOIN individual i ON a.cust_id = i.cust_id) account_ind LEFT OUTER JOIN business b ON account_ind.cust_id = b.cust_id;
--这两个的结果一样
自外连接
SELECT e.fname, e.lname, e_mgr.fname AS mgr_fname, e_mgr.lname AS mgr_lname FROM employee e LEFT OUTER JOIN employee e_mgr
ON e.superior_emp_id = e_mgr.emp_id;
SELECT e.fname, e.lname, e_mgr.fname AS mgr_fname, e_mgr.lname AS mgr_lname FROM employee e RIGHT OUTER JOIN employee e_mgr
ON e.superior_emp_id = e_mgr.emp_id;
上面的这两个例子所展示的结果明显不同,这仅仅是由改变一个关键字引起的,因此,我们在使用外连接时要确定到底使用左外连接还是右外连接。
交叉连接
如果想生成两个表的笛卡儿积,则需要指定交叉连接。
select pt.name, p.product_cd, p.name from product p, product_type pt;
或 select pt.name, p.product_cd, p.name from product p CROSS JOIN product_type pt;(官方建议的标准写法)
自然连接
所谓自然连接,是指依赖多表交叉时的相同列名来推断正确的连接条件。
例如,account 表包含了一个名为 cust_id 的列,它是来自 customer 表的外键,也是 customer 表的主键,我们可以使用自然连接编写一个查询来连接这两个表:
SELECT a.account_id, a.cust_id, c.cust_type_cd, c.fed_id FROM account a NATURAL JOIN customer c;
由于指定了自然连接,因此服务器检查表的定义并给两个表的连接添加了连接条件 a.cust_id = c.cust_id。
条件逻辑
简单的说,条件逻辑是程序执行时从多个路径中选取其一的能力。
case 表达式
查找型 case 表达式
语法如下:
CASE
WHEN C1 THEN E1
WHEN C2 THEN C2
...
WHEN CN THEN EN
[ELSE ED]
END
case 表达式可以返回任意类型的表达式,甚至包括子查询。
SELECT c.cust_id, c.fed_id,
CASE
WHEN c.cust_type_cd = 'I' THEN
(SELECT CONCAT(i.fname, ' ', i.lname) FROM individual i WHERE i.cust_id = c.cust_id)
WHEN c.cust_type_cd = 'B' THEN
(SELECT b.name FROM business b WHERE b.cust_id = c.cust_id)
ELSE 'Unknown'
END name
FROM customer c;
这个查询也可以用外连接,不过使用这个版本的话,服务器只有在需要时才从 individual 和 business 表中读取数据,而不会总是连接所有的表。
简单 case 表达式
语法:
CASE V0
WHEN V1 THEN E1
WHEN V2 THEN E2
...
WHEN VN THEN EN
[ELSE ED]
END
其实就是编程语言里面的 case 语法了。
事务
锁:锁是数据库服务器用来控制数据资源被并行使用的一种机制。当数据库的一些内容被锁定时,任何打算修改(或者可能是读取)这个数据的用户必须等到锁被释放。
锁的粒度:
- 表锁:阻止多用户同时修改同一个表的数据。
- 页锁:阻止多用户同时修改某表中同一页(一页通常是一段2~16KB的内存空间)的数据。
- 行锁:阻止多用户同时修改某表中同一行的数据。
事务:它是一种将多条 SQL 语句聚集到一起,并且能够实现要么所有语句都执行,要么一个都不执行(这个属性称为原子性)。
启动事务
数据库服务器以下面两种方法之一创建事务:
- 一个活跃事务总是和数据库会话相联系,所以没有必要,也没有什么方法能够显示地启动一个事务。当前事务结束时,服务器自动为会话启动一个新的事务。
- 如果不显示地启动一个会话,单个的 SQL 语句会被独立于其他语句自动提交。启动一个事务之前需先提交一个命令。
结束事务
一旦事务启动,不管是通过 start transaction 命令显示地启动还是由数据库服务器隐式地启动,为了持久化数据变化都必须显示地结束事务。可以通过 commit 指令解决这个问题,该指令命令服务器将变化标记为永久性的,进而释放事务中使用的任何资源(也就是页锁或者行锁)。
如果打算撤销自事务启动时所发生的一切变化,读者必须提交 rollback 指令,它命令服务器将数据返回到处理前的状态。同样,会话使用的任何资源都会在 rollback 完成后被释放。
除了提交 commit 或 rollback 指令,结束事务还可以由其他情景触发,要么作为活动的间接结果,要么作为意外的结果:
- 服务器宕机,在这种情况下,服务器重启时事务将会被自动回滚;
- 提交一个SQL模式语句,比如 alter table,这将会引起当前事务提交和一个新事务的启动;
- 提交另一个 start transaction 命令,将会引起前一个事务提交;
- 如果服务器检测到一个死锁并且确定当前事务就是罪魁祸首,那么服务器就会提前结束当前的事务。这种情况下,事务将会被回滚,同时释放错误信息。
索引与约束
索引是寻找资源中特定项目的一种机制。
- 创建索引:ALTER TABLE department ADD INDEX dept_name_idx (name);
- 查看索引:SHOW INDEX FROM department;
- 删除索引:ALTER TABLE department DROP INDEX dept_name_idx;
- 唯一索引:ALTER TABLE department ADD UNIQUE dept_name_idx (name); --这里不需要为主键列创建索引,因为服务器已经为主键检查唯一性。
- 多列索引:ALTER TABLE employee ADD INDEX emp_names_idx (lname, fname); --创建多列索引时,必须仔细考虑哪一列作为第一列,哪一列作为第二列等。
- 索引类型:B树索引,位图索引,文本索引
如何使用索引
服务器通常首先利用索引快速定位特定表中的行,之后再访问相关表提取用户请求的补充信息。不过,如果索引包含满足查询的所有内容,那么服务器就不必访问相关表了。
索引的不足
每个索引事实上都是一个表,因此每次在对表添加或者删除行时,表中的索引必须被修改;当更新行时,受到影响的列的任何索引也必须被修改。因此,索引越多,服务器就需要做越多的工作来保持所有模式对象最新,这将会拖慢服务器处理任务的速度。另外,索引需要磁盘空间,同时也需要管理员耗费一些精力去管理它们。
约束
创建约束
CREATE TABLE product
(product_cd VARCHAR(10) NOT NULL,
name VARCHAR(50) NOT NULL,
product_type_cd VARCHAR(10) NOT NULL,
date_offered DATE,
date_retired DATE,
CONSTRAINT fk_product_type_cd FOREIGN KEY (product_type_cd) REFERENCES product_type (product_type_cd),
CONSTRAINT pk_product PRIMARY KEY (product_cd)
);
上面的这个表里包含了两个约束:一个指定了 product_cd 列作为表的主键,另一个指定了 product_type_cd 列作为来自 product_type 表的外键。
我们也可以先创建表再添加约束:
ALTER TABLE product
ADD CONSTRAINT pk_product PRIMARY KEY (product_cd);
ALTER TABLE product
ADD CONSTRAINT fk_product_type_cd FOREIGN KEY (product_type_cd) REFERENCES product_type (product_type_cd);
删除主键约束或者外键约束:
ALTER TABLE product
DROP PRIMARY KEY;
ALTER TABLE product
DROP FOREIGN KEY fk_product_type_cd;
约束与索引
创建约束有时可能导致自动创建一个索引,不过,数据库服务器对于约束和索引的关系有着不同的处理原则。在实施主键约束,外键约束和唯一约束时,MySQL 会生成新索引;SQL Server 只为主键约束和唯一约束生成新索引,不管外键约束。
级联约束
有了合适的外键约束后,如果想在子表插入新行或者修改行而导致父表中的外键列并无可匹配值,那么服务器会抛出一个错误;如果想删除或者修改一个父行,也会因为外键约束而抛出错误。那么这个时候,我们可以用级联约束命令服务器帮助自己将变化传播到所有子行,这样就保证了数据的完整性。on update cascade
用来指定级联更新,on delete cascade
用来指定级联删除。
ALTER TABLE product
ADD CONSTRAINT fk_product_type_cd FOREIGN KEY (product_type_cd)
REFERENCES product_type (product_type_cd)
ON UPDATE CASCADE
ON DELETE CASCADE;
有了这个版本的约束,当 product_type 表中的一行被更新时,服务器将更新 product 表中的子行,同样,如果 product_type 表中的行被删除,product 表中的子行也将被删除。
SQL学习指南第三篇的更多相关文章
- SQL学习指南第四篇
SQL必知必会(第4版)学习笔记 插入数据 插入有几种方式: 插入完整的行 插入行的一部分 插入某些查询的结果(INSERT SELECT) 注意:省略列 如果表的定义允许,则可以在 INSERT 操 ...
- 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://w ...
- Java工程师学习指南(中级篇)
Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...
- RabbitMQ学习总结 第三篇:工作队列Work Queue
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
- 学习KnockOut第三篇之List
学习KnockOut第三篇之List 欲看此篇---------------------------------------------可先看上篇. 第一步,先搭建一个大概的框架起来 ...
- (转) 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
原文地址: http://www.cnblogs.com/lyhabc/p/4682986.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第三篇,这一篇才真正开始搭建Alwa ...
- Java工程师学习指南(入门篇)
Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
- Java工程师学习指南(初级篇)
Java工程师学习指南 初级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
- Java工程师学习指南(完结篇)
Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...
随机推荐
- 测者的测试技术手册:自动化单元工具EvoSuie的代码覆盖报告
EvoSuite是由Sheffield等大学联合开发的一种开源工具,用于自动生成测试用例集,生成的测试用例均符合Junit的标准,可直接在Junit中运行.得到了Google和Yourkit的支持. ...
- ubuntu 通过apt安装jdk
需要先添加ppa sudo add-apt-repository ppa:webupd8team/java sudo apt-get update 安装jdk8 sudo apt-get instal ...
- anaconda --包管理和环境管理器
前言: 以下所有的命令都Win10环境的 Anaconda Prompt 中 环境管理 创建虚拟环境 conda create --name env_name python 也可以指定 Python ...
- c/c++ gdb 调试带参数的程序
直接gdb pgname 参数1 这种方式,参数1是不会带到gdb里的 1,首先启动程序 gdb pgname 2,设置程序的参数 set args 参数1
- GCD多线程的一个全面的题目
GCD多线程的一个全面的题目
- AXI-Lite总线及其自定义IP核使用分析总结
ZYNQ的优势在于通过高效的接口总线组成了ARM+FPGA的架构.我认为两者是互为底层的,当进行算法验证时,ARM端现有的硬件控制器和库函数可以很方便地连接外设,而不像FPGA设计那样完全写出接口时序 ...
- 【PAT】B1018 锤子剪刀布
抄的柳婼小姐姐的,感觉三个数求最大那里用的真棒 #include <stdio.h> int main() { int N; scanf("%d", &N); ...
- June. 23rd 2018, Week 25th. Saturday
We are who we choose to be. 要成为怎样的人,选择在于自己. From Barry Manilow. I believe that we are who we choose ...
- 多线程控制工具类--倒计时器CountDownLatch的使用(模仿火箭发射)
package com.thread.test.Lock; import java.util.Random; import java.util.concurrent.CountDownLatch; i ...
- Business Intelligence Tools We Recommend 1/4 – Metabase
May 24, 2018 by Arturs Oganesyan-Peel BI is useful. It’s pretty. But it never really matters unless ...