MySql
A. SQL语句
数据库的基本操作
-- 选择要操作的数据库
-- world:数据库名
use world;
-- 显示已存在的数据库列表
show databases;
-- 显示指定数据库下的表的信息
show tables;
-- 显示指定表的列的信息
-- world.country:数据库名.表名
show columns from world.country;
-- 显示指定表的索引信息
-- world.country:数据库名.表名
show index from world.country;
-- 显示指定数据库下的表的详细信息
-- world:数据库名
show table status from world;
-- 显示指定数据库下的表名称以字母'c'开头的表的详细信息
-- world:数据库名
show table status from world like 'c%';
-- 显示数据库表的结构,如:字段名,字段类型等
-- world.country:数据库名.表名
describe world.country;
-- 查看创建表的SQL语句
-- demo.test:数据库名.表名
show create table demo.test;
-- 查看创建存储过程的SQL语句
-- demo.test_proc:数据库名.存储过程名
show create procedure demo.test_proc;
-- 查看创建视图的SQL语句
-- demo.test_view:数据库名.视图名
show create view demo.test_view;
-- 查看创建函数的SQL语句
-- demo.test_fun:数据库名.函数名
show create function demo.test_fun;
-- 查看当前用户的数据库权限
show grants;
-- 查看指定用户的数据库权限
-- admin@localhost:用户名@访问主机
show grants for 'admin'@'localhost';
-- 查询数据库用户信息
select * from mysql.user;
-- 获取服务器版本信息
SELECT VERSION();
-- 获取当前数据库名 (或者返回空)
SELECT DATABASE();
-- 获取当前用户名
SELECT USER();
-- 获取服务器状态
SHOW STATUS;
-- 获取服务器配置变量
SHOW VARIABLES;
例如:
-- 查询自增长值的步长,即每次增加多少,默认为1。
show variables like '%auto_increment%';
-- 设置自增长值每次增加的数值,会影响所有数据表。
set auto_increment_increment=3;
-- 设置自增长值的起始值,会影响所有数据表。
set auto_increment_offset=100;
-- mysql运行在安全模式下时,非主键条件下是无法执行update或者delete命令的
-- 查看安全模式状态
show variables like '%sql_safe_updates%';
-- 设置安全模式为关闭
set sql_safe_updates=off;
-- 获取最近一次向具有identity属性(即自增列)的表插入数据时对应的自增列的值,@@identity是系统定义的全局变量。
select @@identity;
-- LAST_INSERT_ID函数将返回当前连接自增列最新的 insert or update 操作生成的第一个记录的ID。因为其基于Connection的,所以也是线程安全的。
select LAST_INSERT_ID();
DDL:数据定义
a) 数据类型
数值型:
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 字节 | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 字节 | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 字节 | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 字节 | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 字节 | (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 字节 | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 字节 | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
字符串类型
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255字节 | 定长字符串 |
VARCHAR | 0-65535 字节 | 变长字符串 |
TINYBLOB | 0-255字节 | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255字节 | 短文本字符串 |
BLOB | 0-65 535字节 | 二进制形式的长文本数据 |
TEXT | 0-65 535字节 | 长文本数据 |
MEDIUMBLOB | 0-16 777 215字节 | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215字节 | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295字节 | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295字节 | 极大文本数据 |
日和期时间类型
类型 | 大小 | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3字节 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3字节 | '-838:59:59'/'838:59:59' | HH:MM:SS | 时间值或持续时间 |
YEAR | 1字节 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8字节 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 4字节 | 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
b) 创建、删除数据库和表
-- 创建一个名为'test'的数据库
create database test;
-- 创建一个名为'test'的数据库,如果该数据库已存在则不创建,否则再创建
-- 并指定默认字符集为'utf8',字符校对集为'utf8_general_ci'
create database if not exists test default charset utf8 collate utf8_general_ci;
-- 删除名为'test'的数据库
drop database test;
-- 查询所有数据库
Show databases;
-- 使用数据库
Use 数据库名;
-- 更新数据库:
ALTER DATABASE 数据库名 CHARATER SET=UTF8;(修改数据库编码)
-- 创建一个名为'Student'的数据表,如果该数据表已存在则不创建,否则再创建
-- engine:指定数据库引擎为'InnoDB'
-- auto_increment:指定自增列的起始值为1
create table if not exists Student
(
ID int not null auto_increment, #自动增长列
StuNo varchar(32) not null,
StuName varchar(8) not null,
StuSex varchar(8) null,
StuBirthday tinyint null,
CreateTime datetime null,
primary key (ID) #指定主键列
)
engine=InnoDB auto_increment=1 default charset=utf8 collate=utf8_general_ci;
-- 删除数据表 student,该操作会删除所有数据包括表结构、视图、索引、约束等。
drop table test.student;
-- 删除数据表中的所有数据,该操作会删除表中所有的数据,但是会保留表结构、视图、索引、约束等。
truncate table test.student;
-- 创建一个临时表,临时表的创建与数据表的创建类似,只不过需要添加关键字 temporary。
-- 临时表的作用域为当前会话,即当前连接可见,当断开当前连接时会自动销毁,当然也可以手动删除,删除方式与数据表一样。
create temporary table Product
(
ProName varchar(32) not null,
Price decimal(10,3) not null default 0.000
);
-- 复制指定数据表的表结构到创建的新表。
create table test.StudentBak like test.student;
-- 复制指定数据表的表结构及所有数据到创建的新表。
create table test.StudentBak select * from test.student;
c) 表的操作
-- 创建表:
CREATE TABLE [IF EXISTS] 表名(列名 类型,列名 类型);
-- 查看表结构:
DESC 表名;
-- 查看当前数据库所有的表:
SHOW TABLES;
-- 删除表:
DROP TABLE 表名;
-- 查看指定表的创建语句:
SHOW CREATE TABLE 表名; (了解)
-- 修改表:
前缀:ALTER TABLE 表名
-- 添加列:
ALTER TABLE 表名 ADD (
列名 列类型,
列名 列类型,
...
);
-- 修改列类型(如果被修改的列已存在数据,那么新的类型可能会影响到已存在数据):
ALTER TABLE 表名 MODIFY 列名 列类型;
-- 修改列名:
ALTER TABLE 表名 CHANGE 原列名 新列名 列类型;
-- 删除列:
ALTER TABLE 表名 DROP 列名;
-- 修改表名称:
ALTER TABLE 原表名 RENAME TO 新表名;
-- 向指定数据表添加一列,默认添加到数据表字段的末尾。
alter table test.student add column1 varchar(10) null;
-- 向指定数据表添加一列,并设置默认值为:0
alter table demo.chinesecharinfo add column IsUseful tinyint unsigned not null default 0;
-- first关键字用于把添加的列设置为第一列。
alter table test.student add column1 varchar(10) null first;
-- after关键字用于把添加的列设置在指定列的后面,StuSex为指定列的列名。
alter table test.student add column1 varchar(10) null after StuSex;
-- 删除指定列名的列,当数据表仅剩一个字段时,无法进行删除。
alter table test.student drop column1;
-- 修改指定列的数据类型,并设置该列位于指定列名的列之后。
alter table test.student modify column1 char(10) null after CreateTime; -- 关键字column可省略
alter table test.student modify column column1 char(10) null after CreateTime;
-- 修改指定列的列名和数据类型,并设置该列位于指定列名的列之后。
-- column1:为原列名
-- column2:为新的列名
alter table test.student change column1 column2 varchar(10) null after CreateTime;
-- 修改指定列的默认值。
alter table test.student alter column2 set default '123';
-- 删除指定列的默认值。
alter table test.student alter column2 drop default;
-- 修改数据表的存储引擎。
alter table test.student engine = myisam;
alter table test.student engine = InnoDB;
-- 修改数据表的自增长值的起始值。
alter table test.student auto_increment=10;
-- 重建自增长列,当删除数据过多,自增长列的值比较混乱时可以使用,但是重建时如果有新的数据插入,有可能会出现混乱。
alter table test.student drop ID;
alter table test.student add ID int not null auto_increment first;
alter table test.student add primary key(ID);
-- 修改数据表的表名称。
alter table test.student rename to test.StudentBak;
DML:数据管理
a) 事务
b) 插入数据
INTERT INTO 表名(列名1,列名2, ...) VALUES(列值1, 列值2, ...);
在表名后给出要插入的列名,其他没有指定的列等同与插入null值。所以插入记录总是插入一行,不可能是半行。
在VALUES后给出列值,值的顺序和个数必须与前面指定的列对应
INTERT INTO 表名 VALUES(列值1, 列值2)
没有给出要插入的列,那么表示插入所有列。
值的个数必须是该表列的个数。
值的顺序,必须与表创建时给出的列的顺序相同。
// 插入所有列
在数据库中所有的字符串类型,必须使用单引,不能使用双引!
日期类型也要使用单引!
INSERT INTO stu(
number, name, age, gender
)
VALUES(
'ITCAST_0001', 'zhangSan', 28, 'male'
);
// 插入部分列,没有指定的列默认为NULL值
INSERT INTO stu(
number, name
) VAKLUES(
'ITCAST_0002', 'liSi'
)
// 不给出插入列,那么默认为插入所有列!值的顺序要与创建表时列的顺序相同
INSERT INTO stu VALUES(
'ITCAST_0003', 'wangWu', 82, 'female'
);
-- 向数据表中插入数据
insert into student(StuNo,StuName,StuSex,Stubirthday,CreateTime)
select 'A001','小张','男',str_to_date('1988-06-09','%Y-%m-%d'),current_timestamp() union all
select 'A002','小红','女',str_to_date('1990-08-10','%Y-%m-%d'),current_timestamp()
-- 在插入重复的数据时,会直接跳过重复数据的插入。在有自增列或主键的数据表中不起作用,因为自增列和主键都具有唯一性。
insert ignore into test.student(stuno,stuname,stusex,stubirthday,createtime)
values ('A003','小鱼','女','1991-07-07',current_timestamp());
c) 修改数据
- UPDATE 表名 SET 列名1=列值1, 列名2=列值2, ... [WHERE 条件]
- 条件(条件可选的):
条件必须是一个boolean类型的值或表达式:
UPDATE t_person SET gender='男', age=age+1 WHERE sid='1';
运算符:=、!=、<>、>、<、>=、<=、BETWEEN...AND、IN(...)、IS NULL、NOT、OR、AND
UPDATE stu SET name='xxx', age=102
WHERE age >= 18 AND age <= 80
WHERE age BETWEEN 18 AND 80
WHERE name='zhangSan' OR name='liSi'
WHERE name IN ('zhangSan', 'liSi')
WHERE age IS NULL, 不能使用等号
WHERE age IS NOT NULL
d) 删除数据
DELETE FROM 表名 [WHERE 条件];
TRUNCATE TABLE 表名:TRUNCATE是DDL语句,它是先删除drop该表,再create该表,而且无法回滚!
DCL:数据控制
- 一个项目创建一个用户!一个项目对应的数据库只有一个!
- 这个用户只能对这个数据库有权限,其他数据库你就操作不了了!
a) root用户密码修改
修改root用户的密码:
/*登录mysql*/
mysql -uroot -p123
/*切换数据库*/
use mysql
/*修改root用户的密码*/
update user set password=password('1234') where user='root';
如果你忘记了root用户的密码,那么你就无法登录mysql,也就不能修改密码了。这时登录mysql就比较麻烦:
打开一个窗口,执行:mysqld --skip-grant-tables;
这时再开一个窗口来登录mysql:mysql -u root;
然后使用上面相同的方式来修改root用户的密码。
格式:mysqladmin -u用户名 -p旧密码 password 新密码
1、给root加个密码ab12。
首先在DOS下进入目录mysql\bin,然后键入以下命令
mysqladmin -u root -password ab12
注:因为开始时root没有密码,所以-p旧密码一项就可以省略了。
2、再将root的密码改为djg345。
mysqladmin -u root -p ab12 password djg345
b) 创建、删除用户及授权
-- 创建用户
CREATE USER 用户名@IP地址 IDENTIFIED BY '密码'; -- 用户只能在指定的IP地址上登录
CREATE USER 用户名@'%' IDENTIFIED BY '密码'; -- 用户可以在任意IP地址上登录
-- 创建一个新的用户,并设置登录密码
-- test:用户名;localhost:本地主机访问(如果需要其他任意主机访问,请使用通配符'%');123456:用户密码;
create user 'test'@'localhost' identified by '123456';
-- 创建一个新的用户,不指定登录密码,即不需要登录密码
create user 'test01'@'localhost';
-- 查看指定用户的权限
SHOW GRANTS FOR 用户名@IP地址
-- 删除指定的用户
drop user 'test01'@'localhost';
-- 修改用户名
-- test@localhost:要修改的用户名和访问主机
-- test@%:修改为的用户名和访问主机
rename user 'test'@'localhost' to 'test'@'%';
-- 修改用户密码
-- test@localhost:要修改的用户名和访问主机
-- 123456:新的用户密码
set password for 'test'@'localhost' = Password('123456');-- 授予指定用户'test'对于'world'数据库下'country'表的查询权限
-- select:查询权限;world.country:数据库名.表名;'test'@'localhost':用户名@访问主机;
grant select on world.country to 'test'@'localhost';
-- 立即启用修改(默认再次登录才会生效)
flush privileges;
-- 撤销指定用户'test'对于'world'数据库下'country'表的查询权限
-- select:查询权限;world.country:数据库名.表名;'test'@'localhost':用户名@访问主机;
revoke select on world.country from 'test'@'localhost';
-- 立即启用修改(默认再次登录才会生效)
flush privileges;
-- 授予指定用户'test'对于'world'数据库下所有表的查询、新增、修改、删除权限
grant select,insert,update,delete on world.* to 'test'@'localhost';
-- 撤销指定用户'test'对于'world'数据库下所有表的查询、新增、修改、删除权限
revoke select,insert,update,delete on world.* from 'test'@'localhost';
-- 授予指定用户'test'对于'world'数据库下所有表的表结构进行创建、修改、删除权限
grant create,alter,drop on world.* to 'test'@'localhost';
-- 撤销指定用户'test'对于'world'数据库下所有表的表结构进行创建、修改、删除权限
revoke create,alter,drop on world.* from 'test'@'localhost';
-- 授予指定用户'test'对于'world'数据库下所有存储过程的执行权限,并且该用户有权限转授予其他用户
grant execute on world.* to 'test'@'localhost' with grant option;
-- 撤销指定用户'test'对于'world'数据库下所有存储过程的执行权限,转授予权限一并撤销
revoke execute on world.* from 'test'@'localhost';
-- 给用户分派指定数据库上的所有权限
GRANT ALL ON 数据库.* TO 用户名@IP地址;
DQL:数据查询
查询不会修改数据库表记录!
a) 基本查询
1) 字段(列)控制
i. 查询所有列
SELECT * FROM 表名;
SELECT * FROM emp;
--其中“*”表示查询所有列
-- MySQL的WHERE子句默认是不区分大小写的,如果需要区分大小写,就要在字段前加上关键字 binary
select * from student where stuno='a001'; #'1', 'A001', '小张', '男', '1988-06-09', '2018-01-12 12:17:00'
select * from student where binary stuno='a001'; #null
ii. 查询指定列
SELECT 列1 [, 列2, ... 列N] FROM 表名;
SELECT empno, ename, sal, comm FROM 表名;
iii. 完全重复的记录只一次
当查询结果中的多行记录一模一样时,只显示一行。一般查询所有列时很少会有这种情况,但只查询一列(或几列)时,这总可能就大了!
SELECT DISTINCT * | 列1 [, 列2, ... 列N] FROM 表名;
SELECT DISTINCT sal FROM emp;
-- 保查询员工表的工资,如果存在相同的工资只显示一次!
iv. 列运算
数量类型的列可以做加、减、乘、除运算
SELECT sal*1.5 FROM emp;
SELECT sal+comm FROM emp;
字符串类型可以做连续运算
SELECT CONCAT('$', sal) FROM emp;
转换NULL值
有时需要把NULL转换成其它值,例如com+1000时,如果com列存在NULL值,那么NULL+1000还是NULL,而我们这时希望把NULL当前0来运算。
SELECT IFNULL(comm, 0)+1000 FROM emp;
--> IFNULL(comm, 0):如果comm中存在NULL值,那么当成0来运算。
给列起别名
你也许已经注意到了,当使用列运算后,查询出的结果集中的列名称很不好看,这时我们需要给列名起个别名,这样在结果集中列名就显示别名了
SELECT IFNULL(comm, 0)+1000 AS 奖金 FROM emp;
--> 其中AS可以省略
2) 条件控制
i. 条件查询
与前面介绍的UPDATE和DELETE语句一样,SELECT语句也可以使用WHERE子句来控制记录。
* SELECT empno,ename,sal,comm FROM emp WHERE sal > 10000 AND comm IS NOT NULL;
* SELECT empno,ename,sal FROM emp WHERE sal BETWEEN 20000 AND 30000;(between:在……之间)
* SELECT empno,ename,job FROM emp WHERE job IN ('经理', '董事长');
ii. 模糊查询
当你想查询姓张,并且姓名一共两个字的员工时,这时就可以使用模糊查询
* SELECT * FROM emp WHERE ename LIKE '张_';
--> 模糊查询需要使用运算符:LIKE,其中_匹配一个任意字符,注意,只匹配一个字符而不是多个。
--> 上面语句查询的是姓张,名字由两个字组成的员工。
* SELECT * FROM emp WHERE ename LIKE '___'; /*姓名由3个字组成的员工*/
如果我们想查询姓张,名字几个字可以的员工时就要使用“%”了。
SELECT * FROM emp WHERE ename LIKE '张%';
--> 其中%匹配0~N个任意字符,所以上面语句查询的是姓张的所有员工。
SELECT * FROM emp WHERE ename LIKE '%阿%';
--> 千万不要认为上面语句是在查询姓名中间带有阿字的员工,因为%匹配0~N个字符,所以姓名以阿开头和结尾的员工也都会查询到。
SELECT * FROM emp WHERE ename LIKE '%';
--> 这个条件等同与不存在,但如果姓名为NULL的查询不出来!
iii. 正则表达式
-- regexp:用于设置正则表达式匹配项,类似于模糊匹配like。
-- 表示查询名称以字符 'A'(不区分大小写)开头的记录。
select * from world.city where Name regexp '^A';
-- 表示查询名称中包含字符串 'mer' 的记录。
select * from world.city where Name regexp 'mer';
-- 表示查询名称以字符 'a' 或字符 'b' 开头的记录或者以字符 'r' 结尾的记录。
select * from world.city where Name regexp '^[ab]|r$';
b) 排序
1) 升序
SELECT * FROM WHERE emp ORDER BY sal ASC;
--> 按sal排序,升序!
--> 其中ASC是可以省略的
2) 降序
SELECT * FROM WHERE emp ORDER BY comm DESC;
--> 按comm排序,降序!
--> 其中DESC不能省略
3) 使用多列作为排序条件
SELECT * FROM WHERE emp ORDER BY sal ASC, comm DESC;
--> 使用sal升序排,如果sal相同时,使用comm的降序排
c) 聚合函数
聚合函数用来做某列的纵向运算。
1) COUNT
SELECT COUNT(*) FROM emp;
--> 计算emp表中所有列都不为NULL的记录的行数
SELECT COUNT(comm) FROM emp;
--> 云计算emp表中comm列不为NULL的记录的行数
2) MAX
SELECT MAX(sal) FROM emp;
--> 查询最高工资
3) MIN
SELECT MIN(sal) FROM emp;
--> 查询最低工资
4) SUM
SELECT SUM(sal) FROM emp;
--> 查询工资合
5) AVG
SELECT AVG(sal) FROM emp;
--> 查询平均工资
d) 分组查询
分组查询是把记录使用某一列进行分组,然后查询组信息。
例如:查看所有部门的记录数。
SELECT deptno, COUNT(*) FROM emp GROUP BY deptno;
--> 使用deptno分组,查询部门编号和每个部门的记录数
SELECT job, MAX(SAL) FROM emp GROUP BY job;
--> 使用job分组,查询每种工作的最高工资
组条件
以部门分组,查询每组记录数。条件为记录数大于3
SELECT deptno, COUNT(*) FROM emp GROUP BY deptno HAVING COUNT(*) > 3;
e) Limit子句(方言)
-- limit:用于设置返回的记录数。
-- offset:用于设置select语句开始查询的数据偏移量,默认为零。
-- 表示只取前10条数据
select * from world.city limit 10;
-- 表示跃过5条,从第6条数据开始取10条数据。
select * from world.city limit 10 offset 5;
-- 表示从第10条开始取5条数据。
select * from world.city limit 10,5;
--limit取值: (当前页-1) * 每页记录数
B. 完整性约束
主键约束(唯一标识)
****非空
唯一
被引用**(学习外键时)
- 当表的某一列被指定为主键后,该列就不能为空,不能有重复值出现。
- 创建表时指定主键的两种方式:
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;
主键自增长
- 因为主键列的特性是:必须唯一、不能为空,所以我们通常会指定主键类为整型,然后设置其自动增长,这样可以保证在插入数据时主键列的唯一和非空特性。
- 创建表时指定主键自增长
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列设置了非空约束
唯一约束
- 车库某些列不能设置重复的值,所以可以对列添加唯一约束。
- 例如:
CREATE TABLE stu(
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR(20) NOT NULL UNIQUE,
age INT,
gender VARCHAR(10)
);
对sname列设置了非空约束
概念模型
对象模型:可以双向关联,而且引用的是对象,而不是一个主键!
关系模型:只能多方引用一方,而且引用的只是主键,而不是一整行记录。
对象模型:在java中是domain!!!例如:User、Student
is a
has a(关联)
1对1
1对多
多对多
use a
关系模型:在数据库中表!!!
当我们要完成一个软件系统时,需要把系统中的实体抽取出来,形成概念模型。
例如部门、员工都是系统中的实体。概念模型中的实体最终会成为Java中的类、数据库中表。
实体之间还存在着关系,关系有三种:
- 1对多:例如每个员工都从属一个部门,而一个部门可以有多个员工,其中员工是多方,而部门是一方。
- 1对1:例如老公和老婆就是一对一的关系,一个老公只能有一个老婆,而一个老婆只能有一个老公。
- 多对多:老师与学生的关系就是多对多,一个老师可以有多个学生,一个学生可以有多个老师。
概念模型在Java中成为实体类(javaBean)
类就使用成员变量来完成关系,一般都是双向关联!
多对一双向中关联,即员工关联部门,部门也关联员工
class Employee {//多方关联一方
...
private Department department;
}
class Department {//一方关联多方
...
private List employees;
}
class Husband {
...
private Wife wife;
}
class Wife {
...
private Husband
}
class Student {
...
private List teachers
}
class Teacher {
...
private List students;
}
外键约束
- 外键必须是另一表的主键的值(外键要引用主键!)
- 外键可以重复
- 外键可以为空
- 一张表中可以有多个外键!
概念模型在数据库中成为表
数据库表中的多对一关系,只需要在多方使用一个独立的列来引用1方的主键即可
/*员工表*/
create talbe emp (
empno int primary key,/*员工编号*/
...
deptno int/*所属部门的编号*/
);
/*部门表*/
create table dept (
deptno int primary key,/*部门编号*/
...
);
emp表中的deptno列的值表示当前员工所从属的部门编号。也就是说emp.deptno必须在dept表中是真实存在!
但是我们必须要去对它进行约束,不然可能会出现员工所属的部门编号是不存在的。这种约束就是外键约束。
我们需要给emp.deptno添加外键约束,约束它的值必须在dept.deptno中存在。外键必须是另一个表的主键!
语法:CONSTRAINT 约束名称 FOREIGN KEY(外键列名) REFERENCES 关联表(关联表的主键)
创建表时指定外键约束
create talbe emp (
empno int primary key,
...
deptno int,
CONSTRAINT fk_emp FOREIGN KEY(mgr) REFERENCES emp(empno)
);
修改表时添加外键约束
ALERT TABLE emp
ADD CONSTRAINT fk_emp_deptno FOREIGN KEY(deptno) REFERENCES dept(deptno);
修改表时删除外键约束
ALTER TABLE emp
DROP FOREIGN KEY fk_emp_deptno;/*约束名称*/
数据库一对一关系
在表中建立一对一关系比较特殊,需要让其中一张表的主键,即是主键又是外键。
create table husband(
hid int PRIMARY KEY,
...
);
create table wife(
wid int PRIMARY KEY,
...
ADD CONSTRAINT fk_wife_wid FOREIGN KEY(wid) REFERENCES husband(hid)
);
其中wife表的wid即是主键,又是相对husband表的外键!
husband.hid是主键,不能重复!
wife.wid是主键,不能重复,又是外键,必须来自husband.hid。
所以如果在wife表中有一条记录的wid为1,那么wife表中的其他记录的wid就不能再是1了,因为它是主键。
同时在husband.hid中必须存在1这个值,因为wid是外键。这就完成了一对一关系。
*****从表的主键即是外键!
数据库多对多关系
在表中建立多对多关系需要使用中间表,即需要三张表,在中间表中使用两个外键,分别引用其他两个表的主键。
create table student(
sid int PRIMARY KEY,
...
);
create table teacher(
tid int PRIMARY KEY,
...
);
create table stu_tea(
sid int,
tid int,
ADD CONSTRAINT fk_stu_tea_sid FOREIGN KEY(sid) REFERENCES student(sid),
ADD CONSTRAINT fk_stu_tea_tid FOREIGN KEY(tid) REFERENCES teacher(tid)
);
这时在stu_tea这个中间表中的每条记录都是来说明student和teacher表的关系
例如在stu_tea表中的记录:sid为1001,tid为2001,这说明编号为1001的学生有一个编号为2001的老师
sid tid
101 201 /编号为101的学生有一个编号为201的老师/
101 202 /编号为101的学生有一个编号为202的老师/
101 203 /编号为101的学生有一个编号为203的老师/
102 201 /编号为102的学生有一个编号为201的老师/
102 204 /编号为102的学生有一个编号为204的老师/
C. 乱码问题
查看MySQL数据库编码
SHOW VARIABLES LIKE 'char%';
编码解释
- character_set_client:MySQL使用该编码来解读客户端发送过来的数据,例如该编码为UTF8,那么如果客户端发送过来的数据不是UTF8,那么就会出现乱码
character_set_results:MySQL会把数据转换成该编码后,再发送给客户端,例如该编码为UTF8,那么如果客户端不使用UTF8来解读,那么就会出现乱码
其它编码只要支持中文即可,也就是说不能使用latin1控制台乱码问题
插入或修改时出现乱码:
这时因为cmd下默认使用GBK,而character_set_client不是GBK的原因。我们只需让这两个编码相同即可。
因为修改cmd的编码不方便,所以我们去设置character_set_client为GBK即可。查询出的数据为乱码:
这是因为character_set_results不是GBK,而cmd默认使用GBK的原因。我们只需让这两个编码相同即可。
因为修改cmd的编码不方便,所以我们去设置character_set_results为GBK即可。设置变量的语句:
set character_set_client=gbk;
set character_set_results=gbk;
注意,设置变量只对当前连接有效,当退出窗口后,再次登录mysql,还需要再次设置变量。
为了一劳永逸,可以在my.ini中设置:
设置default-character-set=gbk即可。
指定默认编码
我们在安装MySQL时已经指定了默认编码为UTF8,所以我们在创建数据库、创建表时,都无需再次指定编码。
为了一劳永逸,可以在my.ini中设置:
设置character-set-server=utf8即可。
character_set_client | utf8 --> mysql把我们客户端传递的数据都当成是utf8!一是给它传递utf8,二是如果我们传递的是gbk,那么需要修改这个变量为gbk
character_set_connection | utf8
character_set_database | utf8
character_set_results | utf8 --> mysql发送给客户端的数据都是utf8的。一是客户端用utf8编码,二是如果客户端使用gbk来编码,那么需要修改这个变量为gbk的。
character_set_server | utf8
character_set_system | utf8
character_set_client=utf8,无论客户端发送的是什么编码的数据,mysql都当成是utf8的数据!
若客户端发送的是GBK
服务器会当成utf8对待
总结:必然乱码!
处理问题的手段有两种;
让客户端发送utf8的数据(行不通)
把character_set_client修改为gbk
set character_set_client=gbk; --> 只在当前窗口内有效,也就是说,关闭窗口后,再打开,又回到utf8了。
character_set_results=utf8,把数据用什么编码发送给客户端!
若服务器发送给客户端的是utf8的数据
客户端会把它当成gbk,因为我们的小黑屏,只能显示gbk
总结:必然乱码!
处理问题的手段有两种:
让服务器发送gbk的数据:set character_set_results=gbk
让小黑屏使用utf8来解读(行不通)
my.ini
在总配置文件中进行配置,可以一劳永逸
[client]
port=3306
[mysql]
default-character-set=gbk /*它可以一劳永逸!它可以修改三个变量:client、results、connection*/
目前使用字符串设置:
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8
D. 数据库字符校对集
字符校对集,即排序规则,在某个字符集的情况下,字符集的排列顺序应该是什么,称之为校对集。
-- 查看所有的字符校对集
-- 后缀为_bin:表示基于二进制编码的直接比较
-- 后缀为_ci:表示对大小写不敏感的比较
-- 后缀为_cs:表示对大小写敏感的比较
show collation;
E. 备份和恢复数据
数据库 --> sql语句
sql语句 --> 数据库
- 数据库导出SQL脚本(备份数据库内容,并不是备份数据库!)
mysqldump –u用户名 –p密码 数据库名>生成的脚本文件路径
例如:
mysqldump -uroot -p123 mydb1>C:\mydb1.sql
(与mysql.exe和mysqld.exe一样, 都在bin目录下)
注意,不要打分号,不要登录mysql,直接在cmd下运行
注意,生成的脚本文件中不包含create database语句
- 执行SQL脚本
第一种方式
mysql -u用户名 -p密码 数据库<脚本文件路径
例如:先删除mydb1库,再重新创建mydb1库
mysql -uroot -p123 mydb1
注意,不要打分号,不要登录mysql,直接在cmd下运行
第二种方式
登录mysql
source SQL脚本路径
例如:
先删除mydb1库,再重新创建mydb1库
切换到mydb1库
source c:\mydb1.sql
示例:
数据库 --> sql:备份
sql --> 数据库:恢复
mysqldump -uroot -p123 mydb3>c:/a.sql --备份
mysql -uroot -p123 mydb3
F. 多表查询
SQL语句指令顺序:
select *
from emp, dept, (select * from emp)
where
group by
having
order by
limit
合并结果集(了解)
- 要求被合并的表中,列的类型和列数相同
- UNION,去除重复行
UNION ALL,不去除重复行
SELECT * FROM cd
UNION ALL
SELECT * FROM ab;连接查询
a) 分类
内连接
外连接
左外连接
右外连接
全外连接(MySQL不支持)
自然连接(属于一种简化方式)
b) 内连接
-- 方言:
SELECT * FROM 表1 别名1, 表2 别名2 WHERE 别名1.xx=别名2.xx
-- 标准:SELECT * FROM 表1 别名1 INNER JOIN 表2 别名2 ON 别名1.xx=别名2.xx
-- 自然:SELECT * FROM 表1 别名1 NATURAL JOIN 表2 别名2
内连接查询出的所有记录都满足条件。
c) 外连接
-- 左外:
SELECT * FROM 表1 别名1 LEFT OUTER JOIN 表2 别名2 ON 别名1.xx=别名2.xx
-- 左表记录无论是否满足条件都会查询出来,而右表只有满足条件才能出来。左表中不满足条件的记录,右表部分都为NULL
-- 左外自然:
SELECT * FROM 表1 别名1 NATURAL LEFT OUTER JOIN 表2 别名2 ON 别名1.xx=别名2.xx
-- 右外:
SELECT * FROM 表1 别名1 RIGHT OUTER JOIN 表2 别名2 ON 别名1.xx=别名2.xx
-- 右表记录无论是否满足条件都会查询出来,而左表只有满足条件才能出来。右表不满足条件的记录,其左表部分都为NULL
-- 右外自然:
SELECT * FROM 表1 别名1 NATURAL RIGHT OUTER JOIN 表2 别名2 ON 别名1.xx=别名2.xx
-- 全链接:可以使用UNION来完成全链接
子查询
定义:查询中有查询(查看select关键字的个数!)
- 出现的位置:
- where后作为条件存在
- from后作为表存在(多行多列)
- 条件
- 单行单列:SELECT * FROM 表1 别名1 WHERE 列1 [=、>、<、>=、<=、!=] (SELECT 列 FROM 表2 别名2 WHERE 条件)
- 多行单列:SELECT * FROM 表1 别名1 WHERE 列1 [IN, ALL, ANY] (SELECT 列 FROM 表2 别名2 WHERE 条件)
- 单行多列:SELECT * FROM 表1 别名1 WHERE (列1,列2) IN (SELECT 列1, 列2 FROM 表2 别名2 WHERE 条件)
- 多行多列:SELECT * FROM 表1 别名1 , (SELECT ....) 别名2 WHERE 条件