【JavaWeb】16 数据库

本文详细介绍了MySQL数据库的基础知识,包括SQL语言标准、数据定义语言(DDL)、数据操作语言(DML)、数据控制语言(DCL)和数据查询语言(DQL)。内容涵盖了MySQL的启动与关闭、数据库创建、表的定义、各种数据类型、查询操作、完整性约束(如主键、非空和唯一性约束)以及编码和备份恢复。此外,还探讨了多表查询、子查询和连接查询等高级操作。
摘要由CSDN通过智能技术生成

常见数据库

Oracle(神喻):甲骨文(最高!);
DB2:IBM;
SQL Server:微软;
Sybase:赛尔斯;
MySQL:甲骨文;
我们现在所说的数据库泛指“关系型数据库管理系统(RDBMS - Relational database management system)”,即“数据库服务器”。

什么是SQL

SQL(Structured Query Language)是“结构化查询语言”,它是对关系型数据库的操作语言。它可以应用到所有关系型数据库中,例如:MySQL、Oracle、SQL Server等。SQ标准(ANSI/ISO)有:
SQL-92:1992年发布的SQL语言标准;
SQL:1999:1999年发布的SQL语言标签;
SQL:2003:2003年发布的SQL语言标签;

这些标准就与JDK的版本一样,在新的版本中总要有一些语法的变化。不同时期的数据库对不同标准做了实现。
虽然SQL可以用在所有关系型数据库中,但很多数据库还都有标准之后的一些语法,我们可以称之为“方言”。例如MySQL中的LIMIT语句就是MySQL独有的方言,其它数据库都不支持!当然,Oracle或SQL Server都有自己的方言。

语法要求

  • SQL语句可以单行或多行书写,以分号结尾;
  • 可以用空格和缩进来来增强语句的可读性;
  • 关键字不区别大小写,建议使用大写;

分类

DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等;
DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据);
DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别;
DQL(Data Query Language):数据查询语言,用来查询记录(数据)。

mysql基本语句

启动和关闭mysql服务器
启动:net start mysql;
关闭:net stop mysql;
登录:mysql -u root -p 123 -h localhost;
退出:quit或exit;

DDL(数据定义语言)

查看所有数据库名称:SHOW DATABASES;
创建数据库:CREATE DATABASE [IF NOT EXISTS] mydb1;
删除数据库:DROP DATABASE [IF EXISTS] mydb1;
修改数据库编码:ALTER DATABASE mydb1 CHARACTER SET utf8;

常用类型:
int:整型
double:浮点型,例如double(5,2)表示最多5位,其中必须有2位小数,即最大值为999.99;
decimal:泛型型,在表单钱方面使用该类型,因为不会出现精度缺失问题;
char:固定长度字符串类型;
varchar:可变长度字符串类型;
text:字符串类型;
blob:字节类型;
date:日期类型,格式为:yyyy-MM-dd;
time:时间类型,格式为:hh:mm:ss
timestamp:时间戳类型;

创建表:

CREATE TABLE 表名(
  列名 列类型,
  列名 列类型,
  ......
);

查看当前数据库中所有表名称:SHOW TABLES; 
查看指定表的创建语句:SHOW CREATE TABLE emp; 查看emp表的创建语句;
查看表结构:DESC emp; 查看emp表结构;
删除表:DROP TABLE emp; 删除emp表;
修改表:
1.添加列:给stu表添加classname列:
ALTER TABLE stu ADD (classname varchar(100));
2.修改列类型:修改stu表的gender列类型为CHAR(2):
ALTER TABLE stu MODIFY gender CHAR(2);
3.修改列名:修改stu表的gender列名为sex:
ALTER TABLE stu change gender sex CHAR(2);
4.删除列:删除stu表的classname列:
ALTER TABLE stu DROP classname;
5.修改表名称:修改stu表名称为student:
ALTER TABLE stu RENAME TO student;

DML(数据操作语言)

插入数据
INSERT INTO 表名(列名1,列名2, …) VALUES(值1, 值2);
INSERT INTO 表名 VALUES(值1,值2,…);
修改数据
UPDATE 表名 SET 列名1=值1, … 列名n=值n [WHERE 条件];
删除数据
DELETE FROM 表名 [WHERE 条件];
删除表中所有记录:DELETE FROM 表名;
删除stu表,再创建stu表。等同与删除stu表所有记录:TRUNCATE TABLE 表名;
虽然TRUNCATE和DELETE都可以删除表的所有记录,但原理不同。DELETE的效率没有TRUNCATE高。TRUNCATE其实属DDL语句,因为它是先DROP TABLE,再CREATE TABLE。而且TRUNCATE删除的记录是无法回滚的,但DELETE删除的记录是可以回滚的。

DCL(数据控制语言)

创建用户
CREATE USER 用户名@地址 IDENTIFIED BY '密码';

//user1用户只能在localhost这个IP登录mysql服务器
CREATE USER user1@localhost IDENTIFIED BY123;
//user2用户可以在任何电脑上登录mysql服务器
CREATE USER user2@’%’ IDENTIFIED BY123;

给用户授权
GRANT 权限1, … , 权限n ON 数据库.* TO 用户名;

GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON mydb1.* TO user1@localhost;
GRANT ALL ON mydb1.* TO user2@localhost;

撤销授权
REVOKE权限1, … , 权限n ON 数据库.* FORM 用户名;
查看用户权限
SHOW GRANTS FOR 用户名;
删除用户
DROP USER 用户名;
修改用户密码
USE mysql;
UPDATE USER SET PASSWORD=PASSWORD(‘密码’) WHERE User=’用户名’ and Host=’IP’; FLUSH PRIVILEGES;

DQL(数据查询语言)

SELECT selection_list /*要查询的列名称*/
  FROM table_list /*要查询的表名称*/
  WHERE condition /*行条件*/
  GROUP BY grouping_columns /*对结果分组*/
  HAVING condition /*分组后的行条件*/
  ORDER BY sorting_columns /*对结果分组*/
  LIMIT offset_start, row_count /*结果限定*/

条件查询

条件查询就是在查询时给出WHERE子句,在WHERE子句中可以使用如下运算符及关键字:
=、!=、<>、<、<=、>、>=;
BETWEEN…AND;
IN(set);
IS NULL;
AND;
OR;
NOT;

查询性别为女,并且年龄50的记录

SELECT * FROM stu 
WHERE gender='female' AND age<50;

查询学号为S_1001,或者姓名为liSi的记录

SELECT * FROM stu 
WHERE sid ='S_1001' OR sname='liSi';

查询学号为S_1001,S_1002,S_1003的记录

SELECT * FROM stu 
WHERE sid IN ('S_1001','S_1002','S_1003');

查询学号不是S_1001,S_1002,S_1003的记录

SELECT * FROM tab_student 
WHERE s_number NOT IN ('S_1001','S_1002','S_1003');

查询年龄为null的记录

SELECT * FROM stu
WHERE age IS NULL;

查询年龄在20到40之间的学生记录

SELECT * FROM stu
WHERE age>=20 AND age<=40;
或者
SELECT * FROM stu 
WHERE age BETWEEN 20 AND 40;

查询性别非男的学生记录

SELECT * FROM stu
WHERE gender!='male';
或者
SELECT * FROM stu
WHERE gender<>'male';
或者
SELECT * FROM stu
WHERE NOT gender='male';

查询姓名不为null的学生记录

SELECT * FROM stu
WHERE NOT sname IS NULL;
或者
SELECT * FROM stu
WHERE sname IS NOT NULL;

模糊查询

当想查询姓名中包含a字母的学生时就需要使用模糊查询了。模糊查询需要使用关键字LIKE。
查询姓名由5个字母构成的学生记录

SELECT * 
FROM stu
WHERE sname LIKE '_____';
模糊查询必须使用LIKE关键字。其中 “_” 匹配任意一个字母,5个 “_” 表示5个任意字母。

查询姓名由5个字母构成,并且第5个字母为“i”的学生记录

SELECT * 
FROM stu
WHERE sname LIKE '____i';

查询姓名以“z”开头的学生记录

SELECT * 
FROM stu
WHERE sname LIKE 'z%';
其中“%”匹配0~n个任何字母。

查询姓名中第2个字母为“i”的学生记录

SELECT * 
FROM stu
WHERE sname LIKE '_i%';

查询姓名中包含“a”字母的学生记录

SELECT * 
FROM stu
WHERE sname LIKE '%a%';

字段控制查询

去除重复记录
去除重复记录(两行或两行以上记录中系列的上的数据都相同),例如emp表中sal字段就存在相同的记录。当只查询emp表的sal字段时,那么会出现重复记录,那么想去除重复记录,需要使用DISTINCT:

SELECT DISTINCT sal FROM emp;

查看雇员的月薪与佣金之和
因为sal和comm两列的类型都是数值类型,所以可以做加运算。如果sal或comm中有一个字段不是数值类型,那么会出错。
SELECT *,sal+comm FROM emp;
comm列有很多记录的值为NULL,因为任何东西与NULL相加结果还是NULL,所以结算结果可能会出现NULL。下面使用了把NULL转换成数值0的函数IFNULL:

SELECT *,sal+IFNULL(comm,0) FROM emp;

给列名添加别名
在上面查询中出现列名为sal+IFNULL(comm,0),这很不美观,现在我们给这一列给出一个别名,为total:
SELECT *, sal+IFNULL(comm,0) AS total FROM emp;
给列起别名时,是可以省略AS关键字的:

SELECT *,sal+IFNULL(comm,0) total FROM emp;

排序

查询所有学生记录,按年龄升序排序

SELECT *
FROM stu
ORDER BY sage ASC;
或者
SELECT *
FROM stu
ORDER BY sage;

查询所有学生记录,按年龄降序排序

SELECT *
FROM stu
ORDER BY age DESC;

查询所有雇员,按月薪降序排序,如果月薪相同时,按编号升序排序

SELECT * FROM emp
ORDER BY sal DESC,empno ASC;

聚合函数

聚合函数是用来做纵向运算的函数:
COUNT():统计指定列不为NULL的记录行数;
MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

COUNT
当需要纵向统计时可以使用COUNT()。
查询emp表中记录数:

SELECT COUNT(*) AS cnt FROM emp;

查询emp表中有佣金的人数:

SELECT COUNT(comm) cnt FROM emp;
注意,因为count()函数中给出的是comm列,那么只统计comm列非NULL的行数。

查询emp表中月薪大于2500的人数:

SELECT COUNT(*) FROM emp
WHERE sal > 2500;

统计月薪与佣金之和大于2500元的人数:

SELECT COUNT(*) AS cnt FROM emp WHERE sal+IFNULL(comm,0) > 2500;

查询有佣金的人数,以及有领导的人数:

SELECT COUNT(comm), COUNT(mgr) FROM emp;

SUM和AVG
当需要纵向求和时使用sum()函数。
查询所有雇员月薪和:

SELECT SUM(sal) FROM emp;

查询所有雇员月薪和,以及所有雇员佣金和:

SELECT SUM(sal), SUM(comm) FROM emp;

查询所有雇员月薪+佣金和:

SELECT SUM(sal+IFNULL(comm,0)) FROM emp;

统计所有员工平均工资:

SELECT SUM(sal), COUNT(sal) FROM emp;
或者
SELECT AVG(sal) FROM emp;

MAX和MIN
查询最高工资和最低工资:

SELECT MAX(sal), MIN(sal) FROM emp;

分组查询
当需要分组查询时需要使用GROUP BY子句,例如查询每个部门的工资和,这说明要使用部分来分组。

分组查询

查询每个部门的部门编号和每个部门的工资和:

SELECT deptno, SUM(sal)
FROM emp
GROUP BY deptno;

查询每个部门的部门编号以及每个部门的人数:

SELECT deptno,COUNT(*)
FROM emp
GROUP BY deptno;

查询每个部门的部门编号以及每个部门工资大于1500的人数:

SELECT deptno,COUNT(*)
FROM emp
WHERE sal>1500
GROUP BY deptno;

HAVING子句
查询工资总和大于9000的部门编号以及工资和:

SELECT deptno, SUM(sal)
FROM emp
GROUP BY deptno
HAVING SUM(sal) > 9000;
注意,WHERE是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分组;而HAVING是对分组后数据的约束。

LIMIT(MySQL方言)
LIMIT用来限定查询结果的起始行,以及总行数。
查询5行记录,起始行从0开始

SELECT * FROM emp LIMIT 0, 5;
注意,起始行从0开始,即第一行开始

查询10行记录,起始行从3开始

SELECT * FROM emp LIMIT 3, 10;

一页10行,查询第三页

SELECT * FROM emp LIMIT 20,10;
第一个数值的计算方法:(当前页-1*每页记录数

完整性约束

完整性约束是为了表的数据的正确性!如果数据不正确,那么一开始就不能添加到表中。

主键

当某一列添加了主键约束后,那么这一列的数据就不能重复出现。这样每行记录中其主键列的值就是这一行的唯一标识。例如学生的学号可以用来做唯一标识,而学生的姓名是不能做唯一标识的,因为学生有可能同名。
主键列的值不能为NULL,也不能重复
指定主键约束使用PRIMARY KEY关键字

创建表:定义列时指定主键:

CREATE TABLE stu(
		sid	    CHAR(6) PRIMARY KEY,
		sname	VARCHAR(20),
		age		INT,
		gender	VARCHAR(10) 
);

创建表:定义列之后独立指定主键:

CREATE TABLE stu(
		sid	    CHAR(6),
		sname	VARCHAR(20),
		age		INT,
		gender	VARCHAR(10),
		PRIMARY KEY(sid)
);

修改表时指定主键:

ALTER TABLE stu
ADD PRIMARY KEY(sid);

删除主键(只是删除主键约束,而不会删除主键列):

ALTER TABLE stu DROP PRIMARY KEY;

主键自增长

MySQL提供了主键自动增长的功能,这样用户就不用再为是否有主键是否重复而烦恼了。当主键设置为自动增长后,在没有给出主键值时,主键的值会自动生成,而且是最大主键值+1,也就不会出现重复主键的可能了。
创建表时设置主键自增长(主键必须是整型才可以自增长):

CREATE TABLE stu(
		sid INT PRIMARY KEY AUTO_INCREMENT,
		sname	VARCHAR(20),
		age		INT,
		gender	VARCHAR(10)
);

修改表时设置主键自增长:

ALTER TABLE stu 
CHANGE sid 
sid INT AUTO_INCREMENT;

修改表时删除主键自增长:

ALTER TABLE stu 
CHANGE sid 
sid INT;

非空
指定非空约束的列不能没有值,也就是说在插入记录时,对添加了非空约束的列一定要给值;在修改记录时,不能把非空列的值设置为NULL。
指定非空约束:

CREATE TABLE stu(
		sid INT PRIMARY KEY AUTO_INCREMENT,
		sname VARCHAR(10) NOT NULL,
		age		INT,
		gender	VARCHAR(10)
);

当为sname字段指定为非空后,在向stu表中插入记录时,必须给sname字段指定值,否则会报错:

INSERT INTO stu(sid) VALUES(1);
插入的记录中sname没有指定值,所以会报错!

唯一
还可以为字段指定唯一约束:当为字段指定唯一约束后,那么字段的值必须是唯一的。这一点与主键相似。例如给stu表的sname字段指定唯一约束:

CREATE TABLE tab_ab(
	sid INT PRIMARY KEY AUTO_INCREMENT,
	sname VARCHAR(10) UNIQUE
);
 	INSERT INTO sname(sid, sname) VALUES(1001, 'zs');
	INSERT INTO sname(sid, sname) VALUES(1002, 'zs');
  当两次插入相同的名字时,MySQL会报错!

外键
主外键是构成表与表关联的唯一途径
外键是另一张表的主键。例如员工表与部门表之间就存在关联关系,其中员工表中的部门编号字段就是外键,是相对部门表的外键。
外键就是用来约束这一列的值必须是另一张表的主键值。
创建t_user表,指定uid为主键列:

CREATE TABLE t_user(
	uid	INT PRIMARY KEY AUTO_INCREMENT,
	uname	VARCHAR(20) UNIQUE NOT NULL
);

创建t_section表,指定sid为主键列,u_id为相对t_user表的uid列的外键:

CREATE TABLE t_section(
	sid	INT PRIMARY KEY AUTO_INCREMENT,
	sname	VARCHAR(30),
	u_id	INT,
	CONSTRAINT fk_t_user FOREIGN KEY(u_id) REFERENCES t_user(uid)
);

修改t_section表,指定u_id为相对t_user表的uid列的外键:

ALTER TABLE t_section 
ADD CONSTRAINT fk_t_user 
FOREIGN KEY(u_id) 
REFERENCES t_user(uid);

修改t_section表,删除u_id的外键约束:

ALTER TABLE t_section
DROP FOREIGN KEY fk_t_user;

表与表之间的关系

  • 一对一:例如t_person表和t_card表,即人和身份证。这种情况需要找出主从关系,即谁是主表,谁是从表。人可以没有身份证,但身份证必须要有人才行,所以人是主表,而身份证是从表。设计从表可以有两种方案:
    在t_card表中添加外键列(相对t_user表),并且给外键添加唯一约束;
    给t_card表的主键添加外键约束(相对t_user表),即t_card表的主键也是外键。
  • 一对多(多对一):最为常见的就是一对多!一对多和多对一,这是从哪个角度去看得出来的。t_user和t_section的关系,从t_user来看就是一对多,而从t_section的角度来看就是多对一!这种情况都是在多方创建外键
  • 多对多:例如t_stu和t_teacher表,即一个学生可以有多个老师,而一个老师也可以有多个学生。这种情况通常需要创建中间表来处理多对多关系。例如再创建一张表t_stu_tea表,给出两个外键,一个相对t_stu表的外键,另一个相对t_teacher表的外键。

编码

查看MySQL编码
SHOW VARIABLES LIKE 'char%';
在这里插入图片描述

  • character_set_client:服务器使用该编码来解读客户端发送过来的数据;
  • character_set_connection:当执行的是查询语句时,客户端发送过来的数据会先转换成connection指定的编码。该编码与client一致则不会导致乱码。
  • character_set_database:数据库默认编码,在创建数据库时,如果没有指定编码,那么默认使用database编码;
  • character_set_server:MySQL服务器默认编码;
  • character_set_results:响应的编码,即查询结果返回给客户端的编码。

控制台编码
修改character_set_client、character_set_results、character_set_connection为GBK,就不会出现乱码了。但其实只需要修改 character_set_client 和 character_set_results。
控制台的编码只能是GBK,而不能修改为UTF8,这就出现一个问题。客户端发送的数据是GBK,而character_set_client为UTF8,这就说明客户端数据到了服务器端后一定会出现乱码。既然不能修改控制台的编码,那么只能修改character_set_client为GBK了。
服务器发送给客户端的数据编码为character_set_result,它如果是UTF8,那么控制台使用GBK解码也一定会出现乱码。因为无法修改控制台编码,所以只能把character_set_result修改为GBK。
修改character_set_client变量:set character_set_client=gbk;
修改character_set_results变量:set character_set_results=gbk;

设置编码只对当前连接有效,这说明每次登录MySQL提示符后都要去修改这两个编码,但可以通过修改配置文件来处理这一问题。
使用MySQL工具是不会出现乱码的,因为它们会每次连接时都修改character_set_client、character_set_results、character_set_connection的编码。这样对my.ini上的配置覆盖了,也就不会出现乱码了。

MySQL数据库备份与还原

备份和恢复数据

  1. 生成SQL脚本
    在控制台使用mysqldump命令可以用来生成指定数据库的脚本文本,但要注意,脚本文本中只包含数据库的内容,而不会存在创建数据库的语句。所以在恢复数据时,还需要自已手动创建一个数据库之后再去恢复数据。
    mysqldump –u用户名 –p密码 数据库名>生成的脚本文件路径
    现在可以在路径下找到mydb1.sql文件了
    注意,mysqldump命令是在Windows控制台下执行,无需登录mysql
  2. 执行SQL脚本
    执行SQL脚本需要登录mysql,然后进入指定数据库,才可以执行SQL脚本
    执行SQL脚本不只是用来恢复数据库,也可以在平时编写SQL脚本,然后使用执行SQL 脚本来操作数据库。大家都知道,在黑屏下编写SQL语句时,就算发现了错误,可能也不能修改了。所以我建议大家使用脚本文件来编写SQL代码,然后执行。
    SOURCE C:\mydb1.sql
    注意,在执行脚本时需要先行核查当前数据库中的表是否与脚本文件中的语句有冲突。例如在脚本文件中存在create table a的语句,而当前数据库中已经存在了a表,那么就会出错。
    还可以通过下面的方式来执行脚本文件:
    mysql -uroot -p123 mydb1<c:\mydb1.sql
    mysql –u用户名 –p密码 数据库<要执行脚本文件路径
    (这种方式无需登录mysql)

多表查询

合并结果集

作用:合并结果集就是把两个select语句的查询结果合并到一起!
合并结果集有两种方式:
UNION:去除重复记录,例如:SELECT * FROM t1 UNION SELECT * FROM t2;
UNION ALL:不去除重复记录,例如:SELECT * FROM t1 UNION ALL SELECT * FROM t2。
要求:被合并的两个结果:列数、列类型必须相同。
2. 连接查询
连接查询就是求出多个表的乘积,例如t1连接t2,那么查询出的结果就是t1*t2。
连接查询会产生笛卡尔积,假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。
那么多表查询产生这样的结果并不是我们想要的,那么怎么去除重复的,不想要的记录呢,当然是通过条件过滤。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。
你能想像到emp和dept表连接查询的结果么?emp一共14行记录,dept表一共4行记录,那么连接后查询出的结果是56行记录。
也就你只是想在查询emp表的同时,把每个员工的所在部门信息显示出来,那么就需要使用主外键来去除无用信息了。

内连接

  • 方言
    使用主外键关系做为条件来去除无用信息
    SELECT * FROM emp,dept WHERE emp.deptno=dept.deptno;
    上面查询结果会把两张表的所有列都查询出来,也许你不需要那么多列,这时就可以指定要查询的列了。
SELECT emp.ename,emp.sal,emp.comm,dept.dname 
FROM emp,dept 
WHERE emp.deptno=dept.deptno;

还可以为表指定别名,然后在引用列时使用别名即可。

SELECT e.ename,e.sal,e.comm,d.dname 
FROM emp AS e,dept AS d
WHERE e.deptno=d.deptno;
  • 内连接
    上面的连接语句就是内连接,但它不是SQL标准中的查询方式,可以理解为方言!SQL标准的内连接为:
SELECT * 
FROM emp e 
INNER JOIN dept d 
ON e.deptno=d.deptno;

内连接的特点:查询结果必须满足条件。例如我们向emp表中插入一条记录:
其中deptno为50,而在dept表中只有10、20、30、40部门,那么上面的查询结果中就不会出现“张三”这条记录,因为它不能满足e.deptno=d.deptno这个条件。

外连接

外连接的特点:查询出的结果存在不满足条件的可能。

  • 左连接:
SELECT * FROM emp e 
LEFT OUTER JOIN dept d 
ON e.deptno=d.deptno;

左表为主,查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。

  • 右连接
    右表为主,查询左表,左表满足条件的显示,不满足显示NULL。
SELECT * FROM emp e 
RIGHT OUTER JOIN dept d 
ON e.deptno=d.deptno;
  • 全外连接
    MySQL不支持,可以使用UNION连接左连接和右连接的结果集,来达到全外连接的效果。

自然连接

自动找到名称相等的列进行连接:

SELECT * FROM emp NATURAL JOIN dept;
SELECT * FROM emp NATURAL LEFT JOIN dept;
SELECT * FROM emp NATURAL RIGHT JOIN dept;

子查询

子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么就是子查询语句了。
子查询出现的位置:

  • where后,作为条件的一部分;
  • from后,作为被查询的一条表(二次查询);
    当子查询出现在where后作为条件时,还可以使用any、all
  • 子查询结果集的形式:
    单行单列(用于条件)
    单行多列(用于条件)
    多行单列(用于条件)
    多行多列(用于表)

练习:

  1. 工资高于甘宁的员工。
    分析:
    查询条件:工资>甘宁工资,其中甘宁工资需要一条子查询。
第一步:查询甘宁的工资
SELECT sal FROM emp WHERE ename='甘宁'

第二步:查询高于甘宁工资的员工
SELECT * FROM emp WHERE sal > (${第一步})

得到:
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename='甘宁')
  1. 工资高于30部门所有人的员工信息
    分析:
    查询条件:工资高于30部门所有人工资,其中30部门所有人工资是子查询。高于所有需要使用all关键字。
第一步:查询30部门所有人工资
SELECT sal FROM emp WHERE deptno=30;

第二步:查询高于30部门所有人工资的员工信息
SELECT * FROM emp WHERE sal > ALL (${第一步})

得到:
SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30)
  1. 查询工作和工资与殷天正完全相同的员工信息
    分析:
    查询条件:工作和工资与殷天正完全相同,这是子查询
第一步:查询出殷天正的工作和工资
SELECT job,sal FROM emp WHERE ename='殷天正'

第二步:查询出与殷天正工作和工资相同的人
SELECT * FROM emp WHERE (job,sal) IN (${第一步})

得到:
SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename='殷天正')
  1. 查询员工编号为1006的员工名称、员工工资、部门名称、部门地址
    分析:
    查询列:员工名称、员工工资、部门名称、部门地址
    查询表:emp和dept,分析得出,不需要外连接(外连接的特性:某一行(或某些行)记录上会出现一半有值,一半为NULL值)
    条件:员工编号为1006
第一步:去除多表,只查一张表,这里去除部门表,只查员工表
SELECT ename, sal FROM emp e WHERE empno=1006

第二步:让第一步与dept做内连接查询,添加主外键条件去除无用笛卡尔积
SELECT e.ename, e.sal, d.dname, d.loc 
FROM emp e, dept d 
WHERE e.deptno=d.deptno AND empno=1006

第二步中的dept表表示所有行所有列的一张完整的表,这里可以把dept替换成所有行,但只有dname和loc列的表,这需要子查询。
第三步:查询dept表中dname和loc两列,因为deptno会被作为条件,用来去除无用笛卡尔积,所以需要查询它。
SELECT dname,loc,deptno FROM dept;

第四步:替换第二步中的dept
SELECT e.ename, e.sal, d.dname, d.loc 
FROM emp e, (SELECT dname,loc,deptno FROM dept) d 
WHERE e.deptno=d.deptno AND e.empno=1006
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值