WeeklyReview_数据库_20191223-1227


一、sql-基础语法

1、定义

sql(Structured Query Language)
-- 结构化查询语言

2、分类

DDL Data Definition Language: 数据定义语言
DML Data Manipulation Language: 数据操作语言
DCL Data Control Language: 数据控制语言

2.1 DDL Data Definition Language: 数据定义语言

2.1.1 数据库的操作
~ 1.创建数据库
create database 数据库名称; 
    -- 创建指定数据库,如果已经存在会报错
create database if not exists 数据库名称; 
    -- 当指定数据库不存在的时候创建对应数据库
create database if not exists 数据库名称 default charset utf8; 
    -- 创建数据库的时候指定数据文件编码方式

~ 2.删除数据库
drop database 数据库名称;
drop database if EXISTS 数据库名;

~ 3.切换/使用数据库
USE 数据库;  
--切换/使用指定数据库;切换后所有数据库相关操作都是针对此数据库
2.1.2 表的操作
~ 1.创建表(数据库文件是通过表来存数据)
create table if not exists 表名(字段名1 类型1 约束1,字段名2 类型名2 约束2...)

-- 表名:程序员自命名,见名知意,一般前缀加t_/tb_表示
-- 字段名:程序员自命名,见名知意
-- 主键:字段中一定要有一个字段作为主键 可以用来表示唯一一条记录;
--              主键要求不能为空,并且是唯一的,并且是整型
-- 类型名: 必须是当前数据库支持的数据类型,
-- mysql中常用的数据类型:int float double varchar/text(字符串) bit(布尔) date/datatime(日期时间)
-- 约束:not NULL 非空约束,  UNIQUE 唯一约束, DEFAULT 默认值约束, PRIMARY KEY 主键约束, FOREIGN KEY 外键约束,
--              auto_increment(自动增长)
-- 注意:约束可以没有,也可以有多个 

例子:
create table if not EXISTS t_stu(
stu_id int PRIMARY KEY auto_increment,
stu_name VARCHAR(10) not NULL,
stu_birth DATE,
stu_gender BIT DEFAULT 1,
stu_tel VARCHAR(11) UNIQUE
);

~ 2.删除表
-- drop table if EXISTS 表名;  -删除指定表
drop table t_stu;

~ 3.修改表
  3.1 添加字段
-- alter table 表名 add COLUMN 字段名 字段类型 字段约束;
alter table t_stu add COLUMN stu_enname VARCHAR(20),add COLUMN stu_email VARCHAR(20);

  3.2 删除字段
-- alter table 表名 drop column 字段名
alter table t_stu drop COLUMN stu_addr,drop COLUMN stu_email;

  3.3 修改字段名
-- alter table 表名 change 原字段 新字段 新的类型(必写)
alter table t_stu change stu_enname stu_email VARCHAR(20);

2.2 DML Data Manipulation Language: 数据操作语言
(主要提供表中数据的增删改查操作)
2.2.1 insert 添加数据
-- insert into 表名 values (值1,值2,值3...); 按表中字段的顺序依次给每个字段赋值,最终形成一条新的记录
insert into t_stu values(1001,'范闲','1987-03-23',0,13320996307,'[email protected]');

-- INSERT INTO 表名 (字段名1,字段名2,....)  values (值1,值2,....);  -按指定顺序给指定字段赋值,最终形成一条新的记录
insert into t_stu (stu_name,stu_tel,stu_birth) values ('司理理',14255887799,date(now()));
补充: 值的问题(用于mysql的函数)
-- 字符串  - 用引号引起来
-- 日期date   
date(now()) -当前日期  
year(now()) -当前年   
2.2.2 delete 删除数据
-- delete from 表名;   清空当前表

-- delete from 表名 where 条件;   -删除所有满足条件的纪录
delete from t_stu WHERE stu_name = '婉儿';
2.2.3 update 修改数据
-- update 表名 set 字段1=新值1,字段2=新值2,...;  将指定表中所有记录中指定的字段修改成指定的值
2.2.4.select 查询数据
-- SELECT * from 表名; 

-- 结果重新复制(主要针对布尔)
-- select if(字段名,值1,值2) from 表名;   -如果if中对应的字段的值是1,最后结果是值1,否则是值2
-- mysql写法:if(字段,新值1,新值2)

select stu_name,if(stu_gender,'男','女') as 'gender' from t_stu;

-- 通用写法:case 字段 when 值 then 新值1 else 新值2 end
select stu_name,case stu_gender when 1 then '男' else '女' end as'性别' from t_stu;

-- 列合并(查询的时候讲多个字段合并成一个数据返回结果)
-- select concat(字段1,字段2,...)as '新字段名' from 表名;

-- 筛选
-- 上面所有的查询语法的后面都可以加where 条件 对记录进行筛选
-- selelct *from 表名 where 条件;

-- 排序
-- select * from 表名 order by 字段;  将查询结果按指定字段的值从小到大排序
-- order by 字段 asc    升序排序
-- order by 字段 desc   降序排序
补充:sql条件语句的写法
-- 比较运算:= <>(不等于) > < >= <=
-- 逻辑运算:and or not
-- 集合运算:in
-- 范围:between...and....
-- 判断是否为空:is null,is not null
-- 筛选:like %任意字符  _ 单个任意字符
delete from t_stu WHERE stu_name like '范%';
delete from t_stu WHERE stu_tel like '__8%';


二、sql-外键约束和高级查询

1. E.R实体关系图

  • E.R实体关系图是通过图表的形式来表示数据库中表和字段以及表和表之间的关系
  • 表和表之间的关系主要有四种:1对1 1对多 多对1 多对多

2. 外键约束

  • 外键约束:让字段的值取值范围在另外一张表的主键中

  • 怎么添加外键约束:

    1. 保证当前表中有一个字段能够保持另外一张表的主键
    2. 添加外键约束
  • 不同对应关系 外键的添加的要求不同

    1. 一对一:可以添加到任意一张表中
    2. 一对多和多对一: 添加到多的那张表中
    3. 多对多:两张表没有办法简历多对多的对应关系,需要第三张表
例:
alter table tb_student add COLUMN collid int COMMENT '所在学院';   
-- 在学生表中添加新的字段保存学院表的主键
alter table tb_teacher add column collid int;
alter table tb_course add column teaid int;

3. 添加/删除约束

3.1 添加约束

  • 创建表或者添加字段的时候直接在字段后面添加约束
  • 通过修改表的方式添加和删除约束
-- alter table 表名 add constraint 约束索引 约束名(字段); 
 -给指定字段添加指定约束(只能添加唯一约束和主键约束)
alter table tb_student add constraint UNIQUE_collid UNIQUE(collid);
alter table tb_teacher add CONSTRAINT UNIQUE_collid UNIQUE(collid);
alter table tb_course add CONSTRAINT UNIQUE_teaid UNIQUE(teaid);

3.2 删除指定约束:

-- alter table 表名 drop index 约束索引名;
alter table tb_student drop INDEX UNIQUE_collid;
alter table tb_teacher drop index UNIQUE_collid;
alter table tb_course drop index UNIQUE_teaid;

4. 添加/删除外键约束

4.1 添加外键约束

-- alter table 从表名 add CONSTRAINT FK_cid FOREIGN KEY(从表字段名) REFERENCES 主表(主表字段名);
alter table tb_student add CONSTRAINT FK_stucolid FOREIGN KEY(collid) REFERENCES tb_college(collid);
ALTER TABLE tb_teacher add CONSTRAINT FK_teacolid FOREIGN key(collid) references tb_college(collid);
ALTER table tb_course add CONSTRAINT FK_courteaid FOREIGN KEY(teaid) REFERENCES tb_teacher(teaid);

4.2 删除外键约束

alter table 从表名 drop FOREIGN KEY 约束索引名;
alter table tb_student drop FOREIGN key FK_stucolid;
alter table tb_teacher drop FOREIGN key FK_teacolid;

4.3 多对多的外键约束

(两张表没有办法简历多对多的对应关系,需要第三张表)
create table if not EXISTS tb_record(
reid int PRIMARY key auto_increment,
stu_id int comment '学生外键',
cou_id int comment '课程外键',
re_date date comment '选课日期',
score FLOAT,
FOREIGN key(stu_id) REFERENCES tb_student(stuid),
FOREIGN key(cou_id) REFERENCES tb_course(couid)
);

5. 高级查询

5.1 去重

select DISTINCT 字段名 from 表名;
select DISTINCT re_date from tb_record order by re_date;

5.2 限制和分页

-- 限制:查询语句最后加关键字 LIMIT 数字(条数)
select * from tb_record limit 5;

-- 偏移(分页): 
-- select * from 表名 limit M offset N;  -跳过前N条数据获取M条数据(从N+1条数据开始获取M条数据)
-- select * from 表名 limit M,N;     -跳过前M条数据获取N条数据
select * from tb_record order by score desc LIMIT 3 offset 3;

5.3 聚合:

max(),min(),sum(),avg(),count()
select max(score) from tb_record;
select min(score) from tb_record;
select sum(score) from tb_record;  -- 值为空的不参与运算
select avg(score) from tb_record;  -- 值为空的不参与运算
select count(score) from tb_record;   -- 值为空的不参与运算

5.4 分组 group by

-- select 聚合函数(字段名) from 表名 group by(字段);
-- 注意:分组后,除了分组字段意外,其他字段只能聚合操作

-- 每个学生的所有学科的平均分
select stu_id,format(avg(score),2) from tb_record group by stu_id; 

-- 每个学科的平均分
select cou_id,format(avg(score),2) from tb_record GROUP BY cou_id; 

-- 获取每个学生的选课数量
select stu_id,count(cou_id) from tb_record GROUP BY stu_id;

5.5 子查询

将一个查询的结果作为另一个查询的条件或查询对象

  • 第一种查询:将查询结果作为另一个查询的条件
select stu_id,score from tb_record where score = (select max(score) from tb_record);

-- 获取选了2门课程以上的学生的id
select stu_id,count(cou_id) from tb_record GROUP BY stu_id having count(cou_id)>2;

-- 获取选了2门课程以上的学生的姓名
select stuname from tb_student where stuid in (select stu_id from tb_record group by stu_id having count(cou_id)>2);
  • 第二种查询:将一个查询的结果作为另一个查询的查询对象
    -- 注意:第一次查询的结果必须重命名后才能赋给另一个查询作为查询对象
-- 获取分数前三的所有学生的id
select stu_id,score from tb_record where score in(select t.score from (select distinct score from tb_record order by score desc limit 3)as t);

5.6 联表查询/连接查询:同时查多张表的数据

-- select * from 表名1,表名2,表名3 连接条件 查询条件;
-- 注意:如果既有连接条件又有查询条件,查询条件必须置后

-- 查询所有学生的名字和学院名称
select stuname,collname from tb_college,tb_student where tb_college.collid = tb_student.collid;

-- 查询学生每个学科的成绩: 学生姓名 - 学科名 - 分数
select stuname,couname,score from tb_student,tb_course,tb_record where tb_student.stuid = tb_record.stu_id AND tb_course.couid = tb_record.cou_id;


三、sql-内/外连接 授权 事物 视图 索引

1.内连接和外连接

1.1 内连接

  • 内连接有两种写法
    • 方法一:select * from 表1,表2,表3,.....where 连接条件 查询条件;
    • 方法二:select * from 表1 INNER JOIN 表2 on 表2连接条件 INNER JOIN 表3 on 表3的连接条件....where 查询条件
      (在方法二中中间表必须放在最前面)
  • 注意: 如果不写连接条件,最后会形成笛卡尔积现象;
例1:查询薪水超过其所在部门平均薪水的员工的姓名、部门编号和工资
~ 方法一
select c.ename,c.dno,(sal+IFNULL(c.comm,0))as '工资'
FROM 
(select dno,avg(sal)as num FROM tb_emp GROUP BY dno) as t
,tb_emp as c 
WHERE c.dno = t.dno and c.sal>t.num ORDER BY c.dno;

~ 方法二
select c.ename,c.dno,(sal+IFNULL(c.comm,0))as '工资'
FROM 
(select dno,avg(sal)as num FROM tb_emp GROUP BY dno) as t
INNER JOIN tb_emp as c 
ON c.dno = t.dno 
where c.sal>t.num ORDER BY c.dno;

~ 例2:查询部门中薪水最高的人姓名、工资和所在部门名称
select a.ename,(a.sal+IFNULL(a.comm,0))as '工资',b.dname
FROM
(select c.ename,c.sal,c.comm,c.dno
FROM 
(select dno,max(sal)as Top FROM tb_emp GROUP BY dno) as t
INNER JOIN tb_emp as c 
on c.dno = t.dno and c.sal=t.Top ORDER BY dno) as a
INNER JOIN tb_dept as b
on a.dno=b.dno

1.2 外连接:

  • 在mysql中外连接支持左外连接 LEFT JOIN 和右外链接 RIGHT JOIN
例: select * from 表1 left JOIN 表2 on ...: 
- 先将表1的纪录全部取出来,按连接条件依次去连接表2的纪录,
- 表1中的记录找不到条件满足表2记录时那么连接的内容为空

2. DCL Data Control Language: 数据控制语言

DCL主要提供授权和召回授权 以及事务的相关功能

2.1 用户管理(root特权)

1、创建用户(root账号登录数据库后才有创建用户的权限)
-- create user '用户名'@'登录地址'; - 创建指定用户,该用户登录不需要密码
-- create user '用户名'@'登录地址' IDENTIFIED by '密码';
说明:
-- 用户名 - 随便命名;
-- 登录地址 - ip地址/localhost(本机)/%(任意位置)
例:
create user 'user1'@'localhost';
create user 'user2'@'%' identified by '123456';

2、删除用户
-- drop user 用户名;
drop user user2;

2.2 授权管理

1、授权
-- grant 权限类型 on 数据库.表 to 用户名;
-- 说明:
-- 权限类型:insert,delete,update,select,create,drop...., all PRIVILEGES(所有权限)
grant SELECT on school.tb_student to 'user1'@'localhost';
GRANT delete,update on school.tb_student to 'user1'@'localhost'; 

GRANT select on hrs.* to 'user1'@'localhost';

2、召回权限
-- revoke 权限类型 on 数据库.表 from 用户名;
revoke delete on school.tb_student from 'user1'@'localhost';

2.3 事务

  • 如果完成一个任务需要多个操作,但是要求多个操作只要有一个失败,
    那么任务被取消,让数据回到任务开始前的状态;

  • 只有所有的操作都成功了,数据库才更新,这个时候就要用事务控制

  • 语法:

BEGIN;
  操作语句1;
  操作语句2;
  ...
commit;
rollback;

2.4 视图

  • 作用:是用来存储一个sql查询语句的结果.
  • 就相当于给这个查询语句的结果创建一张临时表,但是这张临时表不占物理内存
2.4.1创建视图
-- create view 视图名 as sql查询语句;
use school;

create view vw_score_info as
select stuid,stuname,couid,couname,score FROM
tb_student,tb_record,tb_course
where tb_student.stuid=tb_record.stu_id and tb_record.cou_id=tb_course.couid;
2.4.2 使用视图
-- select * from 视图名;
-- 查询视图和查询表一样
SELECT stuname,avg(score) from vw_score_info group by stuid;

-- 创建学生表的视图:要求视图中不能看到学生的生日,
-- 用学号 姓名 性别 地址和学院作为视图中字段名
use school;

create VIEW vw_stu_info AS
select stuid as'学号',stuname as'姓名',if(stusex,'男','女')as'性别',stuaddr as'地址',
tb_college.collname as'学院'
from tb_student,tb_college
where tb_student.collid = tb_college.collid;

2.5 索引

  • 记录数据的位置,可以提高查询的速度 (牺牲内存换速度)
  • 一般给使用功率较高的字段添加索引 (主键自带唯一索引)
~ 1.给指定字段添加普通索引
-- create index 索引名 on 表名(字段)  

-- 给指定字段添加唯一索引(字段值是唯一的时候才能添加唯一索引)
-- create unique index 索引名 on 表名(字段)  
use school;

-- EXPLAIN:获取sql语句的执行计划(主要用于检测sql语句的性能)
explain select * from tb_student where stuname='项少龙';
explain select * from tb_student where stuid=3755;

create index idx_stuname on tb_student(stuname);

-- 注意:模糊查询的时候以% 和 _ 开头索引无效
explain select * from tb_student where stuname like '%少龙';
explain select * from tb_student where stuname like '_少龙';

~ 2.删除索引
alter table 表名 drop index 索引名;


四、pymysql的使用

1. 和mysql建立连接

连接对象 = pymysql.connect(host,port,user,password)  
-- 和指定mysql建立连接并且返回一个连接对象

-- 说明:
    host - mysql主机地址(localhost表示当前设备上的mysql, 服务器公网ip)
    port - mysql服务端口, 3306
    user - mysql用户
    password  - 用户对应的密码(如果创建用户的时候没有设置密码,这个参数可以不用赋值)
    database - 建立连接后默认操作的数据库
    charset - 设置连接的数据库文件的编码方式
    autocommit - 是否自动提交

con = pymysql.connect(
        host='localhost',
        port=3306,
        user='root',
        password='yuting123456',
        database='school',
        charset='utf8',
        autocommit=True
)

2. 通过连接获取游标对象

with 连接对象.cursor(查询返回值类型=None) as 游标对象:
    数据库操作上下文
    
说明:
    查询返回值类型  - None: 查询结果以元组的形式返回; 
                    pymysql.cursors.DictCursor: 查询结果以字典的形式返回
    数据库操作上下文 - 游标对象(数据库操作)只有在数据库操作上下文才有效

3. 执行sql语句: 游标对象.execute(sql语句)

with con.cursor() as cursor:
   # 数据库操作上下文
   cursor.execute('create database if not exists pyschool;')


五、pymysql-数据库基本操作

1、写一个main方法,其中调用创建表、操作表、查询数据的方法

def main():
# 1.建立连接
    con = pymysql.connect(
            host='localhost',
            user='root',
            password='yuting123456',
            port=3306,
            charset='utf8',
            autocommit=True
    )

 # 2.切换数据库
    with con.cursor() as cursor:
        cursor.execute('use pyschool;')

 # 3.创建表
    create_table(con)

 # 4.操作表
    operate_table(con)

 # 5.查询数据
    query_table(con)

if __name__ == '__main__':
    main()

2、写一个创建表的方法

def create_table(connect):
    """创建表"""
    with connect.cursor() as cursor:
        # 1.=========创建学生表=========
        try:
            sql_str = '''
            create table tb_student
            (
                stuid int auto_increment,
                stuname varchar(10) not null,
                stuage int,
                stusex bit default 1,
                setutel varchar(11),
                primary key (stuid)
            );
            '''
            cursor.execute(sql_str)
        except:
            pass

        # 自定制表
        # table_name = input('表名:')
        # pre = table_name[:3]
        # cnames = []
        # while True:
        #     cname = input('请输入字段名(q-退出):')
        #     if cname == 'q':
        #         break
        #     cnames.append(pre+cname+' text,')
        #
        # str1 = '''
        #     create table if not exists tb_%s
        #     (
        #         %sid int auto_increment,
        #         %s
        #         primary key (%sid)
        #     );
        # '''
        #
        # sql_str = str1 % (
        #     table_name,
        #     table_name[:3],
        #     ' '.join(cnames),
        #     table_name[: 3]
        # )
        # print(sql_str)
        # cursor.execute(sql_str)

3、写一个操作表的方法

def operate_table(connect):
    """增删改"""
    # 1.增
    # sql_str = '''
    #     insert into tb_student
    #     (stuname, stusex, stuage, setutel)
    #     values
    #     ('张三', 1, 30, '17823736452'),
    #     ('stu1', 0, 28, '16728729739');
    # '''
    print('=========插入学生==========')
    sql_str = 'insert into tb_student (stuname, stusex, stuage, setutel) values %s;'
    str2 = ''
    while True:
        name = input('请输入名字:')
        sex = int(input('请输入性别(0/1):'))
        age = int(input('请输入年龄:'))
        tel = input('请输入电话号码:')
        value = input('是否继续添加(y/n):')
        str2 += "('%s', %d, %d, '%s')," % (name, sex, age, tel)

        if value == 'n':
            print(str2[:-1])
            sql_str = sql_str % str2[:-1]
            print(sql_str)
            break

    with connect.cursor() as cursor:
        cursor.execute(sql_str)

4、写一个查询数据的方法

def query_table(connect):
    # 注意: 执行查询的sql语句,查询结果保存在游标对象中的
    # 游标对象.fetchall()
    sql_str = 'select * from tb_student;'
    with connect.cursor(pymysql.cursors.DictCursor) as cursor:
        result = cursor.execute(sql_str)
        print(result, cursor)

        # 注意: cursor中的查询结果,取一个就少一个
        # 1. 游标对象.fetchall() - 获取当前查询的所有的结果
        # all_result = cursor.fetchall()
        # print('查询结果的个数:', len(all_result))
        # for dic in all_result:
        #     print(dic['stuname'])
        #
        # all_result2 = cursor.fetchall()
        # print(all_result2)

        # 2. 游标对象.fetchone()  - 获取当前查询中一条数据
        print(cursor.fetchone())
        print(cursor.fetchone())

        # 3. 游标对象.fetchmany(size)   -- 获取当前查询中指定条数的数据
        print(cursor.fetchmany(2))

你可能感兴趣的:(WeeklyReview_数据库_20191223-1227)