MySQL
基本概念
关系型数据库管理系统:采用关系模型来组织管理数据的数据库系统,把数据保存在不同的表中,而不是将数据放在一个大仓库中
MySQL可以管理n个数据库,一个关系数据库中可以有n个数据表,一个数据表里可以有n条数据。
需要注意的是MySQL是一款数据库管理软件而不是数据库本身。
注意事项:
在使用SQL语句时要注意以下几点:
- 大小写:不严格区分大小写,但是为了明显区分所以书写规则遵从:大写为语句代码,小写为自己写入的内容,例如,
CREATE DATABASE testsql;
- 语句结束符:每个语句都以 分号; 或者 \g 结束
- 类型:强制数据类型,任何数据都有自己的数据类型
- 逗号:创建表的时候最后一行不需要逗号
- 不能使用关键字为数据库 表 和表中数据命名
进入环境
mysql -uusername -ppassword #进入mysql环境
mysql> exit #输入exit,退出mysql环境
学院的ubuntu环境中的mysql账户是mysql -uroot -pqwe123
输入exit时可以不加 分号;
库级操作
显示所有库
SHOW DATABASES;
创建库
CREATE DATABASE databasename;
删除库
DROP DATABASE databasename;
进入数据库
USE databasename;
显示创建库的信息
SHOW CREATE DATABASE databasename;
表级操作
显示所有表
SHOW TABLES;
创建表
CREATE TABLE tablename(field1 datatype,field2 datatype);
显示创建表的信息
SHOW CTREATE TABLE tablename;
删除表
DROP TABLE tablename;
表中数据操作
插入数据
指定字段插入
,可以指定多个字段,表中其余未指定的字段值为NULL
INSERT INTO tablename(field1) VALUES(field1_value);
全字段插入
INSERT INTO tablename VALUES(all_value);
多行插入
INSERT INTO tablename(field1) VALUES (value1), (value2), …;
查询数据
指定字段查询
SELECT field_names FROM tb_name;
全字段查询
SELECT * FROM tb_name;
条件查询
SELECT field_names FROM tb_name WHERE conditions;
conditions条件表达式
修改数据
修改所有数据
UPDATE tb_name SET field_1=value_1
修改多个
UPDATE tb_name SET field_1=value_1, field_2=value_2 …;
修改满足指定条件的数据
UPDATE tb_name SET field_1=value_1 WHERE conditions;
注意:一定要写where条件,不然会修改表中全部数据
删除数据
删除表中所有数据
DELETE FROM tb_name;
删除表中满足条件的数据
DELETE FROM tb_name WHERE conditions;
注意:一定要写where条件,不然会删除表中全部数据
数据类型
创建表的时候,需要在字段后面指定该字段对应的数据类型
数值类型
数值类型 | 特性 |
---|---|
TINYINT | 用一个字节存放整数(0,255) |
SMALLINT | 两个字节 |
MEDIUMINT | 三个字节(0,16777215) |
INT | 四个字节(0,4294967295) |
BIGINT | 八个字节 |
FLOAT(M,N) | 浮点型,含字节数为4,32bit,数值范围为-3.4E38~3.4E38(7个有效位),不加括号默认保存7个有效位。括号内M可以指定总个数,N指定小数位 |
DOUBLE(M,N) | 双精度实型,含字节数为8,64bit数值范围-1.7E308~1.7E308(15个有效位),比FOLAT接收更多的小数位。括号内M可以指定总个数,N指定小数位 |
INT 整型
最常用的数值类型,使用时直接写INT即可。
CREATE TABLE tablename(field1 INT);
字符类型
字符类型 | 特性 |
---|---|
CHAR(size) | 保存固定长度的字符串(可包含字母、数字以及特殊字符)。在括号中指定字符串的长度,最多255个字符 |
VARCHAR(size) | 保存可变长度的字符串(可包含字母、数字以及特殊字符)。在括号中指定字符串的长度,最多255个字符。如果值的长度大于255,则被转换为TEXT类型 |
TINYTEXT / TINYBLOB | 用来存放较短文本数据或二进制数据,最多255个字符 |
TEXT / BLOB | 用来存放长文本数据或二进制数据,最多65535个字符 |
LONGTEXT / LONGBLOB | 用来存放长文本数据或二进制数据,最多4294967295个字符 |
ENUM | enumerate枚举类型的数据是一个包含多个固定值的列表,只能选择这些值(包括NULL),例如,如果希望某个字段包含’A’、‘B’,必须这样定义:ENUM(‘A’,‘B’),只有这些值(或NULL)能够填充到该字段中 |
时间日期类型
时间日期类型 | 特性 |
---|---|
DATE | 日期,2019-02-23 |
TIME | 时间,11:36:30 |
DATETIME | 日期时间,2019-02-23 11:36:30 |
TIMESTAMP | 自动存储记录修改的时间 |
YEAR | 存放的年份 |
问题
SELECT * FROM (SELECT * FROM students ORDER BY age) AS table LIMIT 5;这段代码的错误点在于取别名的时候使用了关键字table,这于sql语句中的TABLE冲突,必须改成别的名字
筛选条件
运算符
比较运算符
运算符 | 意义 |
---|---|
= | 等于( 注意!不是 ==) |
!= 或 <> | 不等于 |
> 和 >= | 大于和大于等于 |
< 和 <= | 小于和小于等于 |
IS NULL | 为空 |
IS NOT NULL | 不为空 |
与、或、非
运算符 | 意义 |
---|---|
AND | 与 |
OR | 或 |
NOT | 非,NOT尽量不要用于数据判断,一般使用于 IS NOT NULL, |
其他操作
排序 ORDER BY
SELECT columns FROM tb_name ORDER BY columns [asc/desc];
默认不写为正序ASC,倒序为DESC
限制 LIMIT
SELECT columns FROM tb_name LIMIT start, count;
LIMIT count,查询前N个,默认从0开始
LIMIT start, count,从第N个开始(索引从0开始),查询N个,
去重 DISTINCT
SELECT DISTINCT columns FROM tb_name;
如果设置多个字段,则去重判定时会以 ‘字段对’ 的形式对重复进行判定,例如,(0,1)和(1,0)就不为重
模糊查询 LIKE
SELECT * FROM students WHERE name LIKE 'Gol%';
任意多个字符: %,任意一个字符: _
小贴士:下划线可以用来匹配由n个字符组成的字符串,例如,'____'可以匹配4个字符组成的任意字符串.
范围查询
连续范围
WHERE columns BETWEEN a AND b
SELECT * FROM students WHERE age BETWEEN 16 AND 21;
#查询age为16到21之间的数据
间隔范围
IN
SELECT * FROM students WHERE age IN (1, 16, 21);
#查询age为1、16、21的数据
聚合与分组
常用聚合函数
函数 | 意义 |
---|---|
COUNT(column) | 统计个数 |
SUM(column) | 求和 |
MAX(column) | 最大值 |
MIN(column) | 最小值 |
AVG(column) | 平均值 |
GROUP_CONCAT(column) | 列出字段全部值 |
只有count可以写 * 在括号内,其他的函数会有问题
GROUP_CONCAT(column) 将字段里的全部值合并成一行
分组查询
将表内字段中的数据进行分组
SELECT group_column1 FROM tb_name
GROUP BY group_column1, group_column2;
如果要查询分组后的字段数据,那么被查询的字段需要出现GROUP BY后面
在分组的情况下,只能出现分组字段和聚合字段,其他的字段没有意义,会报错!
聚合筛选
对聚合出来的数据进行筛选
SELECT group_column, aggregations
FROM tb_name
GROUP BY group_column
HAVING conditions;
aggregations为聚合函数, HAVING后面跟的条件判断中的 字段 需要先被GROUP BY
执行顺序问题
如果一个查询语句中同时包含了ON, WHERE, HAVING,那么他们的执行顺序是:WHERE -> ON -> HAVING
Where是在聚合分组之前对数据进行筛选
Group是在聚合之后再进行筛选
子查询
将一个查询的结果留下来用于下一次查询 ( select 中嵌套 select )
需要满足的要求:1)嵌套在查询内部 ,2)必须始终出现在括号内
#求出学生的平均年龄
select avg(age) from student;
#查找出大于平均年龄的数据
select * from student where age > 18.25;
#将求出的平均年龄的SQL语句用于查找大于平均年龄的语句中
select * from student where age > (select avg(age) from student);
连接查询
在多张表之间查询数据
内连接(inner join)
无条件内连接:
无条件内连接,又名交叉连接/笛卡尔连接
第一张表中的每一项和另一张表的每一项依次组合
SELECT * FROM students JOIN subjects;
JOIN可以将前两个拼接的表再次进行拼接
SELECT * FROM (students JOIN subjects) JOIN grades;
有条件内连接:
在无条件内链接的基础上,加上一个on子句
当连接的时候,筛选出那些有实际意义的记录来进行组合
SELECT * FROM students JOIN subjects ON conditions;
ON后面加的是筛选条件吗,对连接后的总表进行条件筛选
外连接 ( [left | right] join )
左外连接: (以左表为基准)
两张表做连接的时候,在连接条件不匹配的时候
留下左表中的数据,而右表中的数据以NULL填充
SELECT * FROM students LEFT JOIN grades ON conditions;
右外连接: (以右表为基准)
对两张表做连接的时候,在连接条件不匹配的时候
留下右表中的数据,而左表中的数据以NULL填充
SELECT * FROM students RIGHT JOIN grades ON conditions;
问题
如果让A表的id自增且从n开始,B表中的id也自增且但不从n开始,还可以进行联系吗?
学生详情表: 学号,性别,年龄,住址,监护人,联系方式
学生表中的一个学生,在学生详情表中只会有一条数据。
学生详情表中的一条数据,对应学生表中的一个学生
1:一对一和一对多的区别在于,连接的外键是否唯一,就是说学生表里的的dept_id可以重复,它是作为外键连接到学院表,因此学生表里面可以有很多学生在同一个学院。
设置联合主键意为,只有在插入重复的组合时才会报错,例如,已有(0,0)的情况下,插入(0,0)就会报错
表结构修改
表结构修改(alter)
修改表名:
ALTER TABLE tb_name RENAME TO new_name;
修改字段名:
ALTER TABLE tb_name CHANGE COLUMN old_name new_name data_type;
CHANG COLUMN <旧字段名> <新字段名> <数据类型> <*约束类型>
约束类型不写默认是 DEFAULT NULL
修改字段类型:
ALTER TABLE tb_name MODIFY COLUMN field_name data_type;
MODIFY COLUMN <字段名> <数据类型> <*约束类型>
添加字段:
ALTER TABLE tb_name ADD COLUMN field_name data_type;
ADD COLUMN <字段名> <数据类型> <*约束类型>
删除字段:
ALTER TABLE tb_name DROP COLUMN field_name;
约束条件
约束是一种限制,通过对表中的数据做出限制,来确保表中数据的完整性,唯一性
关键字 | 约束类型 |
---|---|
DEFAULT | 设置默认值 |
NOT NULL | 非空 |
UNIQUE KEY | 唯一 |
AUTO_INCREMENT | 自增长 |
PRIMART KEY | 主键 |
FOREIGN KEY | 外键 |
默认约束 (default)
插入数据的时候,如果没有明确为字段赋值,则自动赋予默认值
CREATE TABLE tb(
id INT DEFAULT 'a' ,
name VARCHAR(20)
);
在没有设置默认值的情况下,默认值为NULL
非空约束 (not null)
限制一个字段的值不能为空,INSERT的时候必须为该字段赋值,否则报错
CREATE TABLE tb(
id INT NOT NULL,
name VARCHAR(20)
);
空字符不等于NULL,因此赋值空字符时不会报错
唯一约束 (unique key)
限制一个字段的值不能重复,该字段的数据出现重复时报错
CREATE TABLE tb(
id INT UNIQUE KEY,
name VARCHAR(20)
);
确保字段中值的唯一
主键约束 (primary key)
通常每张表都需要一个主键来体现唯一性,每张表里面只能有一个主键
CREATE TABLE tb(
id INT PRIMARY KEY,
name VARCHAR(20)
);
主键约束 = 非空约束 + 唯一约束
自增长约束 (auto_increment)
自动编号,和主键组合使用,一个表里面只能有一个自增长
CREATE TABLE tb(
id INT AUTO_INCREMENT,
name VARCHAR(20)
);
auto_increment 要求用在主键上,还可以给自增主键设置初始值,例如从1000开始计数
CREATE TABLE tb(
id INT AUTO_INCREMENT,
name VARCHAR(20),
PRIMARY KEY(id))AUTO_INCREMENT = 1000;
外键约束 (foreign key)
保持数据的一致性,外键一般都是通过主键连接,其他例如,非空,唯一也可以
CREATE TABLE tab_a(
id_a INT PRIMARY KEY,
name VARCHAR(20)
);
CREATE TABLE tab_b(
id_b INT PRIMARY KEY,
name VARCHAR(20),
FOREIGN BY (id_b) REFERENCES tab_a(id_a)
);
B有的A一定有, A没有的, B绝对没有
- B表中的id_b字段,只能添加 id_a中已有的数据。
- A表中id_a 是被参照的数据, 不能被修改和删除
表关系
一对一关系(学生<->信息)
学生表 中有学号、姓名、所在班级这三种信息,但学生还有其他的详细信息,例如年龄、性别、住址等等,假设我们将这些详细信息放到一个 学生信息表 里,那么我的的 学生表 里的一个学生就会对应 学生信息表 里的一条详细信息,这种学生和信息一一对应的关系就是 一对一关系
#建立学生表:
CREATE TABLE student(
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name VARCHAR(20) NOT NULL,
s_class VARCHAR(20) NOT NULL
);
#建立学生信息表:
CREATE TABLE student_details(
d_id INT PRIMARY KEY AUTO_INCREMENT,
age INT NOT NULL,
sex VARCHAR(20) NOT NULL,
address VARCHAR(20),
parents VARCHAR(20),
home_num VARCHAR(20),
FOREIGN KEY (d_id) REFERENCES student(s_id)
);
一对一 : 用外键的方式,把两个表的主键关联
学生表中的一个学生,在学生详情表中只会有一条数据
学生详情表中的一条数据,对应学生表中的一个学生
Goullm老师:这个关系中的必然条件是: 有学生才有学生详情 有学生详情就一定有学生 而且一条详情对应一条学生 所以是一对一的
如何使用sql实现: 详情表中的学号和学生表中的学号进行外键联系 这个外键实现了刚才的必然条件
一对多关系(学生<->学院)
学校中一个学院可以有很多的学生,而一个学生只属于某一个学院。
学院与学生之间的关系就是一对多的关系,通过外键关联来实现这种关系
#创建学院表
CREATE TABLE department(
d_id INT PRIMARY KEY AUTO_INCREMENT, # 学院id
d_name VARCHAR(20) NOT NULL # 学院名
);
##创建学生表
CREATE TABLE student(
s_id INT PRIMARY KEY AUTO_INCREMENT, # 学生id
s_name VARCHAR(20) NOT NULL, # 学生名字
dept_id INT NOT NULL, # 所属学院 id
FOREIGN KEY(dept_id) REFERENCES department(d_id) #外键
);
一对多的时候,就是学院和学生的关系,一个学院可以有多个学生,那么在学生表中对应学生所在学院的相关字段就是不唯一的,因此就不设为主键
多对多关系(学生<-选修->选修课)
举例,学生要报名选修课,一个学生可以报名多门课程,一个课程有很多的学生报名,那么学生表和课程表两者就形成了多对多关系。
对于多对多关系,需要创建中间表实现。
#建立课程表:
CREATE TABLE cours(
cours_id INT PRIMARY KEY AUTO_INCREMENT,
cours_name VARCHAR(20) NOT NULL
);
#建立学生表:
CREATE TABLE students(
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name VARCHAR(20) NOT NULL
);
# 选课表 (中间表)
CREATE TABLE select_cours(
sc_s_id INT, #用来记录学生id
sc_cours_id INT, #用来记录课程id
PRIMARY KEY(sc_s_id, sc_cours_id), #联合主键
FOREIGN KEY(sc_s_id) REFERENCES students(s_id),
#关联学生id
FOREIGN KEY(sc_cours_id) REFERENCES cours(cours_id)
#关联课程id
);
MySQL交互
python可以通过pymysql库, 来实现与Mysql数据库的交互, 其主要流程为:
[外链图片转存失败(img-HydI14DA-1564411113365)(E:\Fire\笔记\assets\1551604870597.png)]
操作步骤
导入模块
import pymysql
建立连接
pymysql.connect(**dbconfig)
db_config = {
'host': '127.0.0.1', # IP地址
'port': 3306, # 端口号,int类型
'user': 'root', # 用户名
'password': 'qwe123', # 密码
'db': 'python3', # 数据库名
'charset': 'utf8', # 编码方式
}
conn = pymysql.connect(**dbconfig) # **解包
连接是不能操作数据库的,需要用连接生成游标来操作。
创建游标
cur = connection.cursor()
执行sql语句
cur.execute('SHOW TABLES')
sql语句通过该方法执行,执行插入数据或更改数据语句时,需要灵活运用格式化字符串方法 %s或format,例如
sql = "INSERT INTO bank_users(name,age) VALUES ('{}',{})".format('name',24)
self.cur.execute(sql)
注意,这里由于mysql接收name时需要是字符串,所以要加单引号’{}’
获取结果
cur.fetcall()
输出的结果是一个可迭代对象,接收完成后再次接收返回为空
关闭游标 cur.close()
关闭连接 conn.close()
要点注意
- 在pymysql 中执行的sql语句不需要加 ;
- execute执行完后不是直接得到结果,需要你去主动获取(fetcall)
- 和文件一样,别忘了最后需要关闭游标与连接
- pymysql中的执行方式需要按照事务的执行方法,即回滚(conn.rollback)与提交 (conn.commit)
案例
import pymysql
db_config = {
'host': '127.0.0.1', # IP地址
'port': 3306, # 端口号,int类型
'user': 'root', # 用户名
'password': 'qwe123', # 密码
'db': 'python3', # 数据库名
'charset': 'utf8', # 编码方式
}
# 连接mysql
conn = pymysql.connect(**dbconfig)
# 建立游标
cursor = conn.cursor()
try:
# 执行sql语句,不会返回结果,返回其影响的行数
executes = cursor.execute('SELECT * FROM student')
# 获取结果
values = cursor.fetchall()
# 遍历结果
for value in values:
print(value)
# 提交到数据库,真正把数据插入或者更新到数据
conn.commit()
#发生异常则回滚
except Exception as e:
print(e)
conn.rollback()
finally:
# 使用完成先关闭游标
cursor.close()
# 然后关闭连接
conn.close()
创建用户
创建用户: CREATE USER 'user_name'@'%' IDENTIFIED BY 'password';
# %远程登陆,localhost本地登录
设置用户权限:GRANT ALL ON *.* TO 'user_name'@'%';
查看用户:SELECT host, user FROM mysql.user;
删除用户:DROP USER 'user_name'@'%';
修改密码:SET PASSWORD FOR 'user_name'@'% = PASSWORD('new_password')';
刷新:FLUSH PRIVILEGES;
如果在pip安装时出出现timeout, 系网络延迟过高, 可以采用以下命令安装:pip install i https://mirrors.aliyun.com/pypi/simple/ <库名>
#阿里云里有一些他们的工作人员down在云端的库,如果国外的网站下载的慢可以用这个试试。