MySQL笔记整理

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语句 --> 数据库

  1. 数据库导出SQL脚本(备份数据库内容,并不是备份数据库!)
mysqldump –u用户名 –p密码 数据库名>生成的脚本文件路径
例如:
mysqldump -uroot -p123 mydb1>C:\mydb1.sql  
(与mysql.exe和mysqld.exe一样, 都在bin目录下)

注意,不要打分号,不要登录mysql,直接在cmd下运行
注意,生成的脚本文件中不包含create database语句

  1. 执行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关键字的个数!)

  1. 出现的位置:
  • where后作为条件存在
  • from后作为表存在(多行多列)
  1. 条件
  • 单行单列: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 条件

你可能感兴趣的:(MySQL笔记整理)