- 数据库
1.数据库概念
- 数据库是什么?
- 简单的说就是硬盘上的文件,可以存储和管理数据的仓库。数据的仓库(DBMS),方便查询,可存储的数据量大,保证数据的完整、一直,安全可靠。今天主流数据库为关系型数据库管理系统(RDMS使用表格存储数据)。
- 数据库管理系统(DBMS)的概述,
- 数据库的发展历程(比较复杂不是很理解可以百度下)
- 没有数据库,使用磁盘文件存储数据;
- 层次结构模型数据库;
- 网状结构模型数据库;
- 关系结构模型数据库:使用二维表格来存储数据;
- 关系-对象模型数据库;
MySQL就是关系型数据库
- 常见数据库
- Oracle:甲骨文;
- DB2:IBM;
- SQL Server:微软;
- Sybase:赛尔斯;
- MySQL:甲骨文;
- 理解数据库
- 我们所说的数据是指,“关系型数据库管理系统(RDBMS – Relational database management system)”,即“数据库服务器”,也就是如图紫色的大圈。由管理者Manager来统一管理数据库,比如数据库的一些存储规则和定义等。
正在上传…重新上传取消
- 当我们安装了数据库服务器后,就可以在数据库服务器中创建你的数据库,每个数据库中还可以包含多张表。
正在上传…重新上传取消
数据库表就是一个多行多列的表格。在创建表时,需要指定表的列数,以及列名称,列类型等信息。而不用指定表格的行数,行数是没有上限的。下面是tab_student表的结构:
正在上传…重新上传取消
(表结构)
当把表格创建好了之后,就可以向表格中添加数据了。向表格添加数据是以行为单位的!下面是s_student表的记录:
s_id | s_name | s_age | s_sex |
S_1001 | zhangSan | 23 | male |
S_1002 | liSi | 32 | female |
S_1003 | wangWu | 44 | male |
(表记录)
大家要学会区分什么是表结构,什么是表记录。
- 应用程序与数据库
使用应用程序对数据库进行操作,完成对数据的存储!
正在上传…重新上传取消
2.安装MySQL数据库
- 安装MySQL
参考文档:MySQL安装图解.doc
- MySQL目录结构
- MySQL的数据存储目录为data,data目录通常在C:\Documents and Settings\All Users\Application Data\MySQL\MySQL Server 5.1\data位置。在data下的每个目录都代表一个数据库。
MySQL的安装目录下:
- bin目录中都是可执行文件;
- my.ini文件是MySQL的配置文件;
3.启动和关闭mysql服务器
- 启动:net start mysql(注意后面不加分号)
- 关闭:net stop mysql(注意后面不加分号)
在启动mysql服务后,打开windows任务管理器,会有一个名为mysqld.exe的进程运行,所以mysqld.exe才是MySQL的真正服务器程序
- 客户端登陆、退出mysql
在启动MySQL服务器后,我们需要使用管理员用户登录MySQL服务,然后对服务器进行操作,登录MySQL需要使用MySQL的客户端程序:mysql.exe
- 登录:mysql -uroot -p123 -hlocalhost;
- -u:后面的root是用户名,这里使用的是超级管理员root;
- -p:后面的123是密码,这是在安装MySQL时就已经指定的密码;
- -h:后面给出的localhost是服务器主机名,它是可以省略的,例如:mysql -uroot -p123;
- 退出:quit或exit;
在登录成功后,打开windows任务管理器,会有一个名为mysql.exe的进程运行,所以mysql.exe是客户端程序。
二、SQL语句
- SQL概述
- 什么是SQL语句?
- 一种用于操作数据库的语言,sql语句大致可以分为两大类,针对数据库database和表table的操作。
- SQL语法要求
- SQL语句可以单行或多行书写,以分号结尾;
- 可以用空格和缩进来增强语句的可读性;
- mysql关键字不区别大小写,建议使用大写;
- SQL的标准?
SQL标准(ANSI/ISO)有:
- SQL-92:1992年发布的SQL语言标准;
- SQL:1999:1999年发布的SQL语言标签;
- SQL:2003:2003年发布的SQL语言标签;
这些标准就与JDK的版本一样,在新的版本中总要有一些语法的变化。不同时期的数据库对不同标准做了实现。
- SQL方言
虽然SQL可以用在所有关系型数据库中,但很多数据库还都有标准之后的一些语法,我们可以称之为“方言”。例如MySQL中的LIMIT语句就是MySQL独有的方言,其它数据库都不支持!当然,Oracle或SQL Server都有自己的方言。(举例:比如东北人常说的“忽悠”就是方言,因为像河北、河南、湖北等别的地方的人听不懂的就是方言,当然现在已经被赵本山普及的差不多了,大家都知道了。)
- SQL语句分类
- DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等;(重点)
- 对数据库或表结构的创建、删除、修改等操作!!!
- DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据);(重点)
- 对表的记录进行更新,增、删、改等!!!
- DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别;(重点,难点)
- 对表的记录的查询!!!
- DQL(Data Query Language):数据查询语言,用来查询记录(数据)。
- 对用户的创建及授权等!
- DDL操作数据库
- 基本操作
- 查看所有数据库名称:SHOW DATABASES;
自带的mysql库是系统库,里面保存有账户信息,权限信息,存储过程,event,时区等信息。
- 切换数据库:USE 表名;切换到某数据库;
- 操作数据库
- 创建数据库:CREATE DATABASE 【IF NOT EXISTS】 数据库名字 【CHARSET=utf8】;大括号中是可选内容可写可不写,实际应用的一般不用,区别在于成功与否都不会报错。
- 删除数据库:
- DROP DATABASE [IF EXISTS] 数据库名字;(括号的内容为可选内容,加上的话即使该表不存在也不会报错。)
- 修改数据库编码:(不常用,一般安装的时候会统一设定编码,了解即可)
- ALTER DATABASE 数据库名字 CHARACTER SET utf-8;
- 数据类型,创建表时,指定列的类型
- 常用数据类型:
固长和变长的区别,变长不补0,固长不达到固定长度,会以0补齐;固长要比变长节省空间,因为固长不用单独拿出一个字节来记录数据的长度,取数据的时候要想知道数据的长度,所以会有一个字节或者两个字节来记录数据的长度,而固长不用记录。一般知道数据的长度的用固长合适(如UUID32位,指定ID的位数时),不知道数据长度的用变长(如名字、备注、描述等)。
int:整型
double:浮点型,例如double(5,2)表示最多5位,其中必须有2位小数,即最大值为999.99;
decimal:浮点型,在表单钱方面使用该类型,因为不会出现精度缺失问题;
char:固定长度字符串类型; char(255),数据的长度不足指定长度,补足到指定长度!
varchar:可变长度字符串类型; varchar(65535), zhangSan、用户名、备注、描述时用合适。
text(clob):字符串类型;mysql独有的类型,clob类型是数据库标准里提供的。
> 很小tinytext
> 小text
> 中mediumtext
> 大longtext(相当于4G的内容)
blob:字节类型;二进制的。
> 很小tinyblob 256B
> 小blob 64K
> 中mediumblob 16M
> 大longblob 4G
date:日期类型,格式为:yyyy-MM-dd;
time:时间类型,格式为:hh:mm:ss;
timestamp:时间戳类型,年月日时分秒;
- 对表的操作:
- 创建表:
- CREATE TABLE [IF NOT EXISTS] 表名(
列名 列类型,
列名 列类型,
...
列名 列类型
);
例如:
CREATE TABLE stu( sid CHAR(6), sname VARCHAR(50), age INT, gender VARCHAR(6) ); |
- 查看当前数据库中所有表名称:SHOW TABLES;
- 查看指定表的创建语句:SHOW CREATE TABLE 表名(了解);
- 查看表结构:DESC 表名;
正在上传…重新上传取消
- 删除表:DROP TABLE 表名;
- 修改表:前缀:ALTER TABLE 表名
>> 修改之添加列:
ALTER TABLE 表名 ADD (
列名 列类型,
列名 列类型,
...
);
>> 修改之修改列类型(如果被修改的列已存在数据,那么新的类型可能会影响到已存在数据):ALTER TABLE 表名 MODIFY 列名 列类型;
>> 修改之修改列名:ALTER TABLE 表名 CHANGE 原列名 新列名 列类型;
>> 修改之删除列:ALTER TABLE 表名 DROP 列名;
>> 修改表名称:ALTER TABLE 原表名 RENAME TO 新表名;
- DML(数据库操作语言,它是对表记录的操作,增、删、改!)
- 插入数据,Insert语句:三种方式
在数据库中所有的字符串类型,必须使用单引号,不能使用双引号;日期类型也要使用单引号。
语法1:
INSERT INTO 表名(列名1,列名2, …) VALUES(值1, 值2);
INSERT INTO stu(sid, sname,age,gender) VALUES('st_001', 'zhangSan', 28, 'male'); |
语法2:
因为没有插入age和gender列的数据,所以该条记录的age和gender值上为NULL;
INSERT INTO stu(sid, sname) VALUES('st_002', 'zhangSan'); |
语法3:
INSERT INTO 表名 VALUES(值1,值2,…);
1.没有给出要插入的列,那么表示插入所有的列;2.值的个数必须是该表列的个数;3.值的顺序,必须是创建表时的列的顺序; (一般不建议使用,可读性降低了。)
INSERT INTO stu VALUES('s_003', 'liSi', 32, 'female'); |
注意:所有字符串数据必须使用单引用!
- 修改数据,关键字update
语 法:UPDATE 表名 SET 列名1=值1, … 列名n=值n [WHERE条件]
运算符:=、!=、<>、>、<、>=、<=、BETWEEN...AND、IN(...)、IS NULL、NOT、OR、AND
UPDATE stu SET age=18;效果如下图:整列的数据都更新。
正在上传…重新上传取消
也可以修改多列,UPDATE stu SET age=28,gender=’male’;效果是两列的数据都更新。
正在上传…重新上传取消
修改符合指定条件的数据,条件语句使用关键字WHERE,效果是只要符合条件的数据都更新;
update stu set gender=’female’ where sname=’zhangSan’; |
正在上传…重新上传取消
多个条件的话,可以在WHERE后用OR、AND关键字连接。
Update stu age=29 where sname=’zhangSan’ or sid=’st_003’; |
正在上传…重新上传取消
UPDATE stu SET sname=’wangWu’, age=’30’ WHERE age>28 OR gender=’female’; |
正在上传…重新上传取消
UPDATE stu SET age=48+1 WHERE age BETWEEN 30 AND 40; |
设置年龄在30至40之间包含40的值为49。
正在上传…重新上传取消
关键字in,后面跟的相当于是一个集合。
UPDATE stu SET age=45 WHERE age in(49,28); |
正在上传…重新上传取消
UPDATE stu SET age=NULL WHERE sname=’wangWu’ or sname=’liSi’; |
正在上传…重新上传取消
WHERE条件后只要出现字段=NULL,那么条件永远为false,正确的方式为:字段名 is null;不能出现等号。
正在上传…重新上传取消
正在上传…重新上传取消
UPDATE stu SET age=30 WHERE age IS NOT NULL; |
正在上传…重新上传取消
在sql语句中,=号在set后面是赋值的,在set前面是比较运算符。
UPDATE stu SET age=10 WHERE 1=1; |
正在上传…重新上传取消
- 删除数据:delete
语法1:DELETE FROM 表名 [WHERE 条件];
delete from stu where sname=’liSi’; |
正在上传…重新上传取消
语法2:TRUNCATE TABLE 表名:TRUNCATE是DDL语句,它是先删除drop该表,再create该表。而且无法回滚!!!
- DCL(理解)
- 创建用户
语法:CREATE USER 用户名@IP地址 IDENTIFIED BY ‘密码’;
>>用户只能在指定的IP地址上登录;
CREATE USER用户名@’%’ IDENTIFIED BY ‘密码’;
>>用户可以在任意IP地址上登录;
CREATE USER zhangsan@localhost IDENTIFIED BY 'password'; |
CREATE USER zhangsan@’%’ IDENTIFIED BY 'password'; |
- 给用户授权
语法:GRANT 权限1,…,权限n ON 数据库.* TO 用户名@IP地址
>>给用户分派在指定数据库上的指定的权限;
>> 例如;GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON mydb1.* TO user1@localhost;
给user1用户分派在mydb1数据库上的create、alter、drop、insert、update、delete、select权限
GRANT ALL ON 数据库.* TO 用户名@IP地址;
>>给用户分派指定数据库上的所有权限;
- 撤销授权
语法: REVOKE 权限1, … , 权限n ON 数据库.* FROM 用户名@IP地址;
>> 撤消指定用户在指定数据库上的指定权限;
>> 例如:REVOKE CREATE,ALTER,DROP ON mydb1.* FROM user1@localhost;
撤消user1用户在mydb1数据库上的create、alter、drop权限
- )查看用户权限
语法:SHOW GRANTS FOR 用户名@IP地址
>> 查看指定用户的权限
- 删除用户
语法:DROP USER 用户名@IP地址
- 修改用户密码
语法:USE mysql;
UPDATE USER SET PASSWORD=PASSWORD(‘密码’) WHERE User=’用户名’ and Host=’IP’;
FLUSH PRIVILEGES;
UPDATE USER SET PASSWORD=PASSWORD('1234') WHERE User='user2' and Host=’localhost’; FLUSH PRIVILEGES; |
三、DQL数据库查询语言
查询不会修改数据库表记录!
- 基本查询
1.1字段(列)控制
- 查询所有列
SELECT * FROM 表名;
>> 其中‘*’表示查询所有列;
正在上传…重新上传取消
- 查询指定列
SELECT 列1,列2,…列N FROM 表名;
正在上传…重新上传取消
- 完全重复的记录只显示一次
当查询结果中的多行记录一模一样时,只显示一行。一般查询所有列时很少会有这种情况,但只查询一列(或几列)时,这种可能就大了。
查询stu表的年龄字段,如果有重复的只显示一次。
正在上传…重新上传取消
- 列运算
- 数量类型的列可以做加、减、乘、除运算
SELECT age*1.5 FROM stu; SELECT age+10 FROM stu;
正在上传…重新上传取消
- 字符串类型的可以做连续运算
SELECT CONCAT(‘aaa’,sname) FROM stu;
正在上传…重新上传取消
- 转换NULL值
比如下图查询结果,有时需要把NULL转换成其它值,例如age+100时,如果age列存在NULL值,那么NULL+100还是NULL,而我们这时希望把NULL当成0来运算。
正在上传…重新上传取消
SELECT IFNULL(age,0)+100 FROM stu;
>>IFNULL(age,0);如果age中存在NULL值,那么当成0来运算
正在上传…重新上传取消
- 给列起别名
你也许已经注意到了,当使用列运算后,查询出的结果集中的列名称很不好看,这时我们需要给列起个别名,这样在结果集中列名就会显示别名了
SELECT IFNULL(age,0)+100 AS 年龄 FROM stu;
正在上传…重新上传取消
- 条件查询
与前面介绍的UPDATE和DELETE语句一样,SELECT语句也可以使用WHERE子句来控制记录。
- SELECT sid,sname,age,gender FROM stu WHERE age > 20 AND age IS NOT NULL;
正在上传…重新上传取消
- SELECT sid,sname,age FROM stu WHERE age BETWEEN 20 AND 40;(包含20和40)
正在上传…重新上传取消
- SELECT sid,sname,age FROM stu WHERE age IN (20,40);
正在上传…重新上传取消
- 模糊查询
当你想查询姓张,并且名字一共两个字的学生时,这时就可以使用模糊查询。
- SELECT * FROM stu2 WHERE sname LIKE ‘张_’
>>模糊查询需要使用关键字:LIKE,其中_代表任意一个字符,注意,只代表一个字符而不是多个。
>>上面的语句查询的是姓张的,名字有两个字组成的学生。
- SELECT * FROM stu2 WHERE sname LIKE '___'; /*姓名由3个字组成的学生*/
如果我们想查询姓张,名字几个字都可以的学生时就要使用“%”了。
- SELECT * FROM stu2 WHERE sname LIKE '张%';
>>其中%匹配0~N个任意字符,所以上面语句查询的是姓张的所有学生。
- SELECT * FROM emp WHERE sname LIKE '%阿%';
>>千万不要认为上面语句是在查询姓名中间带有阿字的学生,因为%匹配0~N个字符,所以姓名以阿开头和结尾的学生也都会查询到。
- SELECT * FROM stu2 WHERE sname LIKE '%';
>>这个条件等同与不存在,但如果姓名为NULL的查询不出来!
- 排序
- 升序
SELECT * FROM stu ORDER BY age ASC;
正在上传…重新上传取消
>>按age排序,升序
>>其中ASC是可以省略的,数据库默认就是按照升序排序。
- 降序
SELECT * FROM stu ORDER BY age DESC;
正在上传…重新上传取消
>>按age排序,降序!
>>其中DESC不能省略
使用多列作为排序条件
SELECT * FROM stu ORDER BY sid ASC, age DESC;
正在上传…重新上传取消
>>使用sid升序排,如果age相同时,使用age的降序排
- 聚合函数
聚合函数用来做某列的纵向运算。(比如:求出数据一共多少条?这列数据中的最大值或最小值、平均值、和等的统计运算)
- COUNT():统计指定列不为NULL的记录行数;
- MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
- MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
- SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
- AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;
- COUNT
- 查询stu表中的记录数;
>> SELECT COUNT(*) FROM stu;
- 查询stu表中有年龄值的人数;注意因为count()函数给出的是age列,那么只统计age列非NULL的行数。
>> SELECT COUNT(age) cnt FROM stu;
- 查询stu表中年龄大于30的人数;
>>SELECT COUNT(age) FROM stu WHERE age>30;
- 查询符合where条件的,有sid的人数,有年龄值的人数;
>>SELECT COUNT(sid),COUNT(age) FROM stu WHERE gender=’male’;
- MAX和MIN
- 查询大年龄和最小年龄
>>SELECT MAX(age), MIN(age) FROM stu;
- SUM
当需要纵向求和时使用sum()函数
- 查询所有学生的年龄和;
>>SELECT SUM(age) FROM stu;
- 查询所有学生年龄各增加5岁之后的和;
>>SELECT SUM(IFNULL(age,0)+5) FROM stu;
- AVG
- 统计所有学生的平均年龄
>>SELECT AVG(age) FROM stu;
- 分组查询
当需要分组查询时使用GROUP BY子句,例如查询不同性别的学生年龄和,这说明要使用分组按组来查询。
例如:
- 查询不同性别的年龄和。(使用性别分组,男和女,来还运算出年龄和)
>>SELECT SUM(age) FROM stu GROUP BY gender;
- 查询不同性别的学生人数;(使用性别分许,男和女,来运算出人数)
>>SELECT COUNT(*) FROM stu GROUP BY gender;
- HAVING子句
- 以部门分组,查询每组记录数。条件为记录数大于1
SELECT age,COUNT(*) FROM stu GROUP BY age HAVING COUNT(*) > 1;
注意:一条语句中要用到这里所有的关键字的话,一般的执行顺序是:select、from、where、group by、having、order by。首先是去除条件使用where关键字,然后是再分组,然后是分组后的条件having,最后是排序。
- Limit子句(方言)
LIMIT用来限定查询结果的起始行,以及总行数。
- 例如:查询起始行为第5行,一共查询3行记录
SELECT * FROM stu LIMIT 4, 3;
>>其中4表示从第5行开始,其中3表示一共查询3行。即第5、6、7行记录。
- 查询10行记录,起始行从3开始;
SELECT * FROM stu LIMIT 3, 10;
- 分页查询
如果一页的记录数为10条,希望查看第3页记录,应该怎么查呢?
首先第一页起始行为0,一共查询10行;
第二页记录起始行为10,一共查询10行;
第三页记录起始行为20,一共查询10行;
SELECT * FROM stu LIMIT 20,10;
(当前页-1) * 每页记录数
(3-1) * 10
四、完整性约束
完整性约束是为了表的数据的正确性!如果数据不正确,那么一开始就不能添加到表中。
- 主键约束(唯一标识)
特点是:非空;唯一;被引用。
当某一列添加了主键约束后,那么这一列的数据就不能重复出现,是唯一的。这样每行记录中其主键列的值就是这一行的唯一标识。例如学生的学号可以用来做唯一标识,而学生的姓名是不能做唯一标识的,因为学生有可能同名的。
主键列的值不能为NULL,也不能重复!
指定主键约束使用PRIMARY KEY关键字
创建表时指定主键的两种方式:
- 方式一:创建表时定义列时指定主键:
CREATE TABLE stu(
sid CHAR(6) PRIMARY KEY,
sname VARCHAR(20),
age INT,
gender VARCHAR(10)
);
指定sid列为主键列,即为sid列添加主键约束
- 方式二:创建表时定义列之后独立指定主键:
CREATE TABLE stu(
sid CHAR(6),
sname VARCHAR(20),
age INT,
gender VARCHAR(10),
PRIMARY KEY(sid)
);
指定sid列为主键列,即为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;
- 测试主键自增长:(注意会报错的!)
INSERT INTO stu VALUES(NULL, 'zhangSan',23,'male');
INSERT INTO stu(sname,age,gender) VALUES('zhangSan',23,'male');
- 非空约束
因为某些列不能设置为NULL值,所以可以对列添加非空约束。
例如:
CREATE TABLE stu(
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR(20) NOT NULL,
age INT,
gender VARCHAR(10)
);
对sname字段指定为非空后,在向stu表中插入记录时,必须给sname字段指定值,否则会报错:
插入的记录中sname没有指定值,所以会报错!
- 唯一约束
还可以为字段指定唯一约束!当为字段指定唯一约束后,那么字段的值必须是唯一的。这一点与主键相似!
例如:
CREATE TABLE stu(
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR(20) NOT NULL UNIQUE,
age INT,
gender VARCHAR(10)
);
对stu表的sname列设置了唯一约束;
- 概念模型
当我们要完成一个软件系统时,需要把系统中的实体抽取出来,形成概念模型。
例如部门、员工都是系统中的实体。概念模型中的实体最终会成为Java中的类、数据库中表。
实体之间还存在着关系,关系有三种:
* 1对多:例如每个员工都从属一个部门,而一个部门可以有多个员工,其中员工是多方,而部门是一方。
* 1对1:例如老公和老婆就是一对一的关系,一个老公只能有一个老婆,而一个老婆只能有一个老公。
* 多对多:老师与学生的关系就是多对多,一个老师可以有多个学生,一个学生可以有多个老师。
概念模型在Java中成为实体类(javaBean)
类就使用成员变量来完成关系,一般都是双向关联!
多对一双向中关联,即员工关联部门,部门也关联员工
class Employee {//多方关联一方
...
private Department department;
}
class Department {//一方关联多方
...
private List<Employee> employees;
}
class Husband {
...
private Wife wife;
}
class Wife {
...
private Husband
}
class Student {
...
private List<Teacher> teachers
}
class Teacher {
...
private List<Student> students;
}
- 外键约束
主外键是构成表与表关联的唯一途径!
外键是另一张表的主键!例如学生表与班级表之间就存在关联关系,其中学生表中的班级编号字段就是外键,是相对班级表的外键。
正在上传…重新上传取消
我们再来看BBS系统中:用户表(t_user)、分类表(t_section)、帖子表(t_topic)三者之间的关系。
正在上传…重新上传取消
例如在t_section表中sid为1的记录说明有一个分类叫java,版主是t_user表中uid为1的用户,即Zhangsan!
例如在t_topic表中tid为2的记录是名字为“Java是咖啡”的帖子,它是java版块的帖子,它的作者是wangwu。
外键就是用来约束这一列的值,必须是另一张表的主键值!!!一个表可以有多个外键!!!
外键可以重复,但外键必须是另一个表的主键,外键可以为NULL!!!
- 创建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%';
正在上传…重新上传取消
因为当初安装时指定了字符集为UTF8,所以所有的编码都是UTF8。
- 控制台编码
- MySQL工具
使用MySQL工具是不会出现乱码的,因为它们会每次连接时都修改character_set_client、character_set_results、character_set_connection的编码。这样对my.ini上的配置覆盖了,也就不会出现乱码了。
六、MySQL数据库备份与还原
备份和恢复数据
- 生成SQL脚本
在控制台使用mysqldump命令可以用来生成指定数据库的脚本文本,但要注意,脚本文本中只包含数据库的内容,而不会存在创建数据库的语句!所以在恢复数据时,还需要自已手动创建一个数据库之后再去恢复数据。
mysqldump –u用户名 –p密码 数据库名>生成的脚本文件路径 |
正在上传…重新上传取消
现在可以在C盘下找到mydb1.sql文件了!
注意,mysqldump命令是在Windows控制台下执行,无需登录mysql!!!
- 执行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!
七、多表查询
多表查询有如下几种:
- 合并结果集;
- 连接查询
- 内连接
- 外连接
- 左外连接
- 右外连接
- 全外连接(MySQL不支持)
- 自然连接
- 子查询
- 合并结果集
- 作用:合并结果集就是把两个select语句的查询结果合并到一起!
- 合并结果集有两种方式:
- UNION:去除重复记录,例如:SELECT * FROM t1 UNION SELECT * FROM t2;
- UNION ALL:不去除重复记录,例如:SELECT * FROM t1 UNION ALL SELECT * FROM t2。
- 要求:被合并的两个结果:列数、列类型必须相同。
- 连接查询
连接查询就是求出多个表的乘积,例如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[q1] ; |
正在上传…重新上传取消
上面查询结果会把两张表的所有列都查询出来,也许你不需要那么多列,这时就可以指定要查询的列了。
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;[q2] |
- 内连接
上面的连接语句就是内连接,但它不是SQL标准中的查询方式,可以理解为方言!SQL标准的内连接为:
SELECT * FROM emp e INNER[q3] JOIN dept d ON[q4] e.deptno=d.deptno; |
内连接的特点:查询结果必须满足条件。例如我们向emp表中插入一条记录:
正在上传…重新上传取消
其中deptno为50,而在dept表中只有10、20、30、40部门,那么上面的查询结果中就不会出现“张三”这条记录,因为它不能满足e.deptno=d.deptno这个条件。
- 外连接(左连接、右连接)
外连接的特点:查询出的结果存在不满足条件的可能。
左连接:
SELECT * FROM emp e LEFT OUTER[q5] JOIN dept d ON e.deptno=d.deptno; |
左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。
这么说你可能不太明白,我们还是用上面的例子来说明。其中emp表中“张三”这条记录中,部门编号为50,而dept表中不存在部门编号为50的记录,所以“张三”这条记录,不能满足e.deptno=d.deptno这条件。但在左连接中,因为emp表是左表,所以左表中的记录都会查询出来,即“张三”这条记录也会查出,但相应的右表部分显示NULL。
正在上传…重新上传取消
- 右连接
右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示NULL。例如在dept表中的40部门并不存在员工,但在右连接中,如果dept表为右表,那么还是会查出40部门,但相应的员工信息为NULL。
SELECT * FROM emp e RIGHT OUTER JOIN dept d ON e.deptno=d.deptno; |
正在上传…重新上传取消
- 自然连接
大家也都知道,连接查询会产生无用笛卡尔积,我们通常使用主外键关系等式来去除它。而自然连接无需你去给出主外键等式,它会自动找到这一等式:
- 两张连接的表中名称和类型完成一致的列作为条件,例如emp和dept表都存在deptno列,并且类型一致,所以会被自然连接找到!
当然自然连接还有其他的查找条件的方式,但其他方式都可能存在问题!
SELECT * FROM emp NATURAL JOIN dept;[q6] SELECT * FROM emp NATURAL LEFT JOIN dept;[q7] SELECT * FROM emp NATURAL RIGHT JOIN dept;[q8] |
- 子查询
子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么就是子查询语句了。
- 子查询出现的位置:
- where后,作为条件的一部分;
- from后,作为被查询的一条表;
- 当子查询出现在where后作为条件时,还可以使用如下关键字:
- any
- all
- 子查询结果集的形式:
- 单行单列(用于条件)
- 单行多列(用于条件)
- 多行单列(用于条件)
- 多行多列(用于表)
练习:
- 工资高于甘宁的员工。
分析:
查询条件:工资>甘宁工资,其中甘宁工资需要一条子查询。
第一步:查询甘宁的工资
SELECT sal FROM emp WHERE ename='甘宁' |
第二步:查询高于甘宁工资的员工
SELECT * FROM emp WHERE sal > (${第一步}) |
结果:
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename='甘宁') |
- 子查询作为条件
- 子查询形式为单行单列
- 工资高于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 [q9] (SELECT sal FROM emp WHERE deptno=30) |
- 子查询作为条件
- 子查询形式为多行单列(当子查询结果集形式为多行单列时可以使用ALL或ANY关键字)
- 查询工作和工资与殷天正完全相同的员工信息
分析:
查询条件:工作和工资与殷天正完全相同,这是子查询
第一步:查询出殷天正的工作和工资
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='殷天正') |
- 子查询作为条件
- 子查询形式为单行多列
- 查询员工编号为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 |
- 子查询作为表
- 子查询形式为多行多列
练习:
1. 查询出部门编号为30的所有员工
2. 所有销售员的姓名、编号和部门编号。
3. 找出奖金高于工资的员工。
4. 找出奖金高于工资60%的员工。
5. 找出部门编号为10中所有经理,和部门编号为20中所有销售员的详细资料。
6. 找出部门编号为10中所有经理,部门编号为20中所有销售员,还有即不是经理又不是销售员但其工资大或等于20000
的所有员工详细资料。
8. 无奖金或奖金低于1000的员工。
9. 查询名字由三个字组成的员工。
10.查询2000年入职的员工。
11. 查询所有员工详细信息,用编号升序排序
12. 查询所有员工详细信息,用工资降序排序,如果工资相同使用入职日期升序排序
13. 查询每个部门的平均工资
14. 查询每个部门的雇员数量。
15. 查询每种工作的最高工资、最低工资、人数
--16. 显示非销售人员工作名称以及从事同一工作雇员的月工资的总和,并且要满足从事同一工作的雇员的月工资合计
大于50000,输出结果按月工资的合计升序排列
--7. 有奖金的工种。
select * from 表名;
-
- 去除完全重复的行:distinct。放在列名之前。
- 列运算。任何值与null相加都得null。
正在上传…重新上传取消
正在上传…重新上传取消
处理null值;使用ifnull函数转换成0.
-
- 给列起别名;as也可以省略。
正在上传…重新上传取消
正在上传…重新上传取消
条件控制。
1)条件查询,模糊查询,_ _
正在上传…重新上传取消
2)排序Order by,升序asc,降序desc;
多列排序;正在上传…重新上传取消
3)聚合函数(纵向运算)
count(列名)计算表中有效行数,所有列都不为null的
sum(列名),求和。
max(求最大值)
min(求最小值)
avg(求平均数)
4)分组查询,group bye分组;
正在上传…重新上传取消
分组前条件where,分组后的查询条件使用having
limit分页:
正在上传…重新上传取消
sql语句的执行顺序,
正在上传…重新上传取消
- 的
正在上传…重新上传取消
[q1]在多表查询中,在使用列时必须指定列所从属的表,例如emp.deptno表示emp表的deptno列。
[q2]其中AS是可以省略的
[q3]INNER可以省略,MySQL默认的连接方式就是内连接
[q4]不使用WHERE,而是使用ON
[q5]OUTER可以省略
[q6]内连接
[q7]左连接
[q8]右连接
[q9]大于所有