决战Python之巅(二十)-MySql

概述

数据库(DataBase)

数据库即存放数据的仓库(DataBase),只不过这个仓库是在计算机存储设备上,而且数据(Data)是按一定的格式存放的。
数据库是长期存放在计算机内、有组织、可共享的数据集合。
数据库中的数据按一定的数据模型组织、描述和储存,具有较小的冗余度、较高的数据独立性和易扩展性,并可为各种 用户共享。

数据库管理系统

在了解了Data与DB的概念后,如何科学地组织和存储数据,如何高效获取和维护数据成了关键。
这就用到了一个系统软件—数据库管理系统,如MySQL、Oracle、SQLite、Access、MS SQL Server等。
管理数据的工具有很多种,不止mysql一个。关于分类其实可以从各个纬度来进行划分,但是我们最常使用的分类还是根据他们存取数据的特点来划分的,主要分为关系型和非关系型
可以简单的理解为,关系型数据库需要有表结构,非关系型数据库是key-value存储的,没有表结构

	关系型:如sqllite,db2,oracle,access,sql server,MySQL,注意:sql语句通用
	非关系型:mongodb,redis,memcache

数据库服务器、数据管理系统、数据库、表与记录的关系(重点)

记录多个字段的信息组成一条记录,即文件中的一行内容,如:1 朱葛 13234567890 22

:userinfo,studentinfo,courseinfo(即文件

数据库:db(即文件夹

数据库管理系统:如mysql(是一个软件)

数据库服务器:一台计算机(对内存要求比较高)

总结:

数据库服务器:运行数据库管理软件

数据库管理软件:管理-数据库

数据库:即文件夹,用来组织文件/表

表:即文件,用来存放多行内容/多条记录

SQL

上述提到MySQL等软件可以接受命令,并做出相应的操作,由于命令中可以包含删除文件、获取文件内容等众多操作,对于编写的命令就是是SQL语句。SQL,是结构化语言(Structured Query Language)的缩写,SQL是一种专门用来与数据库通信的语言。(昨天面试问到了这个问题- -什么是SQL?)

SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统,SQL语言由IBM开发。SQL语言分为3种类型:

  • 1、DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如create、drop、 alter
  • 2、DML语句 数据库操纵语言: 插入数据insert、删除数据delete、更新数据update、查询数据select
  • 3、DCL语句 数据库控制语言: 例如控制用户的访问权限grant、revoke

MySql使用

百度
请自行百度,这里就不赘述。

用户管理

#创建用户
    create user '用户名'@'IP地址' identified by '密码';
#删除用户
    drop user '用户名'@'IP地址';
#修改用户
    rename user '用户名'@'IP地址' to '新用户名'@'IP地址';
#修改密码
    set password for '用户名'@'IP地址' = Password('新密码');

用户和IP

		用户名@IP地址         	用户只能在改IP下才能访问
        用户名@192.168.1.%   	用户只能在改IP段下才能访问(通配符%表示任意)
        用户名@%             	用户可以再任意IP下访问(默认IP地址为%)

授权管理

#查看权限
	show grants for '用户名'@ 'IP地址';
#授权
	grant  权限 on 数据库.to '用户'@ 'IP地址';
#取消权限
	revoke 权限 on 数据库.from '用户'@ 'IP地址';

所有权限

	    all privileges  		除grant外的所有权限
        select          		仅查权限
        select,insert   		查和插入权限
        ...
        usage                   无访问权限
        alter                   使用alter table
        alter routine           使用alter procedure和drop procedure
        create                  使用create table
        create routine          使用create procedure
        create temporary tables 使用create temporary tables
        create user             使用create user、drop user、rename user和revoke  all privileges
        create view             使用create view
        delete                  使用delete
        drop                    使用drop table
        execute                 使用call和存储过程
        file                    使用select into outfile 和 load data infile
        grant option            使用grant 和 revoke
        index                   使用index
        insert                  使用insert
        lock tables             使用lock table
        process                 使用show full processlist
        select                  使用select
        show databases          使用show databases
        show view               使用show view
        update                  使用update
        reload                  使用flush
        shutdown                使用mysqladmin shutdown(关闭MySQL)
        super                   使用change master、kill、logs、purge、master和set global。还允许mysqladmin调试登陆
        replication client      服务器位置的访问
        replication slave       由复制从属使用

授权对象

对于目标数据库以及内部其他:
        数据库名.*           数据库中的所有
        数据库名.表          指定数据库中的某张表
        数据库名.存储过程     指定数据库中的存储过程
        *.*                所有数据库

特殊

#将数据读取到内存中,从而立即生效。
flush privileges

数据库操作

#数据库的增删改查
#增:
create database 数据库名称 charset utf8;
#查:
show databases;
#改:
alter database 数据库名称 charset latin1;
#删: 
drop database 数据库名称;

这里呢,主要注意的地方是,在创建库时,最好用下面这个语句:create database 数据库名称 default charset utf8;,其中default charset utf8的意思是默认使用默认使用utf8编码格式,这可以避免以后可能出现的编码问题。

数据表操作

在对某个数据库下的表进行操作时,首先要进入这个数据库。就像要处理某个文件,必须先进入那个文件所在的文件夹。
进入语句:use 数据库名称;

新建表

#语法:
create table 表名(
字段名1 数据类型[(宽度) 约束条件],
字段名2 数据类型[(宽度) 约束条件],
字段名3 数据类型[(宽度) 约束条件]
);

#注意:
1. 在同一张表中,字段名是不能相同
2. 宽度和约束条件可选
3. 字段名和数据类型是必须的

数据类型

数值类型

MySQL支持所有标准SQL数值数据类型。

这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。

关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。

MySQL支持的整数类型有TINYINT、MEDIUMINT和BIGINT。下面的表显示了需要的每个整数类型的存储和范围。

对于小数的表示,MYSQL分为两种方式:浮点数和定点数。浮点数包括float(单精度)和double(双精度),而定点数只有decimal一种,在mysql中以字符串的形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。

BIT数据类型保存位字段值,并且支持MyISAM、MEMORY、InnoDB和BDB表。
在这里插入图片描述

日期和时间类型

表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。

每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
在这里插入图片描述

字符串类型

在这里插入图片描述
这里要注意的是char和varchar的区别,日常中也是这两种用的最多。
char和 varchar类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
char列的长度固定为创建表是声明的长度,范围(0-255);而varchar的值是可变长字符串范围(0-65535)。

enum和set

enum中文名称叫枚举类型,它的值范围需要在创建表时通过枚举方式显示。enum只允许从值集合中选取单个值,而不能一次取多个值。

set和enum非常相似,也是一个字符串对象,里面可以包含0-64个成员。根据成员的不同,存储上也有所不同。set类型可以允许值集合中任意选择1或多个元素进行组合。对超出范围的内容将不允许注入,而对重复的值将进行自动去重。
在这里插入图片描述

约束条件

为了防止不符合规范的数据进入数据库,在用户对数据进行插入、修改、删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数据库中存储的数据正确、有效、相容。

约束条件与数据类型的宽度一样,都是可选参数,主要分为以下几种:

# NOT NULL :非空约束,指定某列不能为空; 
# UNIQUE : 唯一约束,指定某列或者几列组合不能重复
# PRIMARY KEY :主键,指定该列的值可以唯一地标识该列记录
# FOREIGN KEY :外键,指定该行记录从属于主表中的一条记录,主要用于参照完整性

not null

是否可空,null表示空,非字符串

  • not null - 不可空
  • null - 可空
default

我们约束某一列不为空,如果这一列中经常有重复的内容,就需要我们频繁的插入,这样会给我们的操作带来新的负担,于是就出现了默认值的概念。

默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值:

create table 表名 (字段名1 数据类型(长度) not null default 默认值);

primary key

主键为了保证表中的每一条数据的该字段都是表格中的唯一值。换言之,它是用来独一无二地确认一个表格中的每一行数据。
主键可以包含一个字段或多个字段。当主键包含多个栏位时,称为组合键 (Composite Key),也可以叫联合主键。
主键可以在建置新表格时设定 (运用 CREATE TABLE 语句),或是以改变现有的表格架构方式设定 (运用 ALTER TABLE)。
主键必须唯一,主键值非空;可以是单一字段,也可以是多字段组合。

1.单字段主键:
create table 表名 (字段名1 数据类型(长度) primary key #主键);
2.多字段主键:
create table 表名 (
字段名1 数据类型(长度),
字段名2 数据类型(长度)primary key(字段名1,字段名2)
);

auto_increment

约束字段为自动增长,被约束的字段必须同时被key约束。

create table 表名(
字段名1 int primary key auto_increment
);
#这样在插入数据时,不指定字段1的值,则自动从1增长。

对于自增长字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长。这是应该使用truncate清空表,比起delete一条一条地删除记录,truncate是直接清空表,在删除大表时用它。

查看表

查看表结构有两种方式:
describe [tablename];这种方法和desc [tablename];效果相同;可以查看当前的表结构
虽然desc命令可以查看表的定义,但是其输出的信息还不够全面,为了得到更全面的表定义信息,有时候就需要查看创建表的SQL语句,使用show create table语法。除了可以看到表定义之外,还可以看到engine(存储引擎)和charset(字符集)等信息。(\G选项的含义是是的记录能够竖向排列,以便更好的显示内容较长的记录。)

修改表结构

语法:
1. 修改表名
      ALTER TABLE 表名 
                      RENAME 新表名;

2. 增加字段
      ALTER TABLE 表名
                      ADD 字段名  数据类型 [完整性约束条件…],
                      ADD 字段名  数据类型 [完整性约束条件…];
                            
3. 删除字段
      ALTER TABLE 表名 
                      DROP 字段名;

4. 修改字段
      ALTER TABLE 表名 
                      MODIFY  字段名 数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                      CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                      CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];

5.修改字段排列顺序/在增加的时候指定字段位置
    ALTER TABLE 表名
                     ADD 字段名  数据类型 [完整性约束条件…]  FIRST;
    ALTER TABLE 表名
                     ADD 字段名  数据类型 [完整性约束条件…]  AFTER 字段名;
    ALTER TABLE 表名
                     CHANGE 字段名  旧字段名 新字段名 新数据类型 [完整性约束条件…]  FIRST;
    ALTER TABLE 表名
                     MODIFY 字段名  数据类型 [完整性约束条件…]  AFTER 字段名;

删除表

DROP TABLE 表名;

多表结构的创建与分析

找出两张表之间的关系

分析步骤:
#1、先站在左表的角度去找
是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段(通常是id)

#2、再站在右表的角度去找
是否右表的多条记录可以对应左表的一条记录,如果是,则证明右表的一个字段foreign key 左表一个字段(通常是id)

#3、总结:
#多对一:
如果只有步骤1成立,则是左表多对一右表
如果只有步骤2成立,则是右表多对一左表

#多对多
如果步骤1和2同时成立,则证明这两张表时一个双向的多对一,即多对多,需要定义一个这两张表的关系表来专门存放二者的关系

#一对一:
如果1和2都不成立,而是左表的一条记录唯一对应右表的一条记录,反之亦然。
这种情况很简单,就是在左表foreign key右表的基础上,将左表的外键字段设置成unique即可

建立表之间的关系

#一对多或称为多对一(假设表1的字段1与表2的字段2有关系)
create table 表名1(
字段1 int primary key auto_increment,
);

create table 表名2(
字段2 int primary key auto_increment,
字段1_字段2 int not null,
foreign key(字段1_字段2) references 表名1(字段1)
on delete cascade
on update cascade
);

#多对多
create table 表名1(
字段1 int primary key auto_increment,
);

create table 表名2(
字段2 int primary key auto_increment,
);

#这张表就存放表1与表2的关系,即查询二者的关系查这表就可以了
create table [表名2]2[表名2](
字段3 int not null unique auto_increment,
字段1_id int not null,
字段2_id int not null,
constraint fk_字段1 foreign key(字段1_id) references 表名1(字段1)
on delete cascade
on update cascade,
constraint fk_字段2 foreign key(字段2_id) references 表名2(字段2)
on delete cascade
on update cascade,
primary key(字段1_id,字段2_id)
);

#一对一
#关联方式:foreign key+unique
create table 表名1(
字段1 int primary key auto_increment,
);

create table 表名2(
字段2 int primary key auto_increment,
字段1_字段2 int not null unique,
foreign key(字段1_字段2) references 表名1(字段1)
on delete cascade
on update cascade
);

数据记录操作

插入数据insert

1. 插入完整数据(顺序插入)
    语法一:
    INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(1,2,3…值n);

    语法二:
    INSERT INTO 表名 VALUES (1,2,3…值n);

2. 指定字段插入数据
    语法:
    INSERT INTO 表名(字段1,字段2,字段3) VALUES (1,2,3);

3. 插入多条记录
    语法:
    INSERT INTO 表名 VALUES
        (1,2,3…值n),
        (1,2,3…值n),
        (1,2,3…值n);
        
4. 插入查询结果
    语法:
    INSERT INTO 表名(字段1,字段2,字段3…字段n) 
                    SELECT (字段1,字段2,字段3…字段n) FROM2
                    WHERE 条件语句;

更新数据update

语法:
    UPDATE 表名 SET
        字段1=1,
        字段2=2,
        WHERE 条件语句;

删除数据delete

语法:
    DELETE FROM 表名 
        WHERE 条件语句;

查询数据select

单表查询

SELECT DISTINCT 字段1,字段2... FROM 表名
                              WHERE 条件
                              GROUP BY field
                              HAVING 筛选
                              ORDER BY field
                              LIMIT 限制条数

执行优先级:

from
where
group by
select
distinct
having
order by
limit

即:
1.找到表:from
2.拿着where指定的约束条件,去文件/表中取出一条条记录
3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
4.执行select(去重)
5.将分组的结果进行having过滤
6.将结果按条件排序:order by
7.限制结果的显示条数

简单查询

#已有表如下
company.employee
    员工id      id                  int             
    姓名        emp_name            varchar
    性别        sex                 enum
    年龄        age                 int
    入职日期     hire_date           date
    岗位        post                varchar
    职位描述     post_comment        varchar
    薪水        salary              double
    办公室       office              int
    部门编号     depart_id           int

#简单查询
    SELECT id,emp_name,sex,age,hire_date,post,post_comment,salary,office,depart_id 
    FROM employee;

    SELECT * FROM employee;

    SELECT emp_name,salary FROM employee;

#避免重复DISTINCT
    SELECT DISTINCT post FROM employee;    

#通过四则运算查询
    SELECT emp_name, salary*12 FROM employee;
    SELECT emp_name, salary*12 AS Annual_salary FROM employee;
    SELECT emp_name, salary*12 Annual_salary FROM employee;

#定义显示格式
   CONCAT() 函数用于连接字符串
   SELECT CONCAT('姓名: ',emp_name,'  年薪: ', salary*12)  AS Annual_salary 
   FROM employee;
   
   CONCAT_WS() 第一个参数为分隔符
   SELECT CONCAT_WS(':',emp_name,salary*12)  AS Annual_salary 
   FROM employee;

   结合CASE语句:
   SELECT
       (
           CASE
           WHEN emp_name = 'jingliyang' THEN
               emp_name
           WHEN emp_name = 'alex' THEN
               CONCAT(emp_name,'_BIGSB')
           ELSE
               concat(emp_name, 'SB')
           END
       ) as new_name
   FROM
       employee;

where过滤

where字句中可以使用:

  1. 比较运算符:> < >= <= <> !=
  2. between 80 and 100 值在80到100之间
  3. in(80,90,100) 值是80或90或100
  4. like ‘e%’
    通配符可以是%或_,
    %表示任意多字符
    _表示一个字符
  5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
#1:单条件查询
    SELECT emp_name FROM employee
        WHERE post='sale';
        
#2:多条件查询
    SELECT emp_name,salary FROM employee
        WHERE post='teacher' AND salary>10000;

#3:关键字BETWEEN AND
    SELECT emp_name,salary FROM employee 
        WHERE salary BETWEEN 10000 AND 20000;

    SELECT emp_name,salary FROM employee 
        WHERE salary NOT BETWEEN 10000 AND 20000;
    
#4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS)
    SELECT emp_name,post_comment FROM employee 
        WHERE post_comment IS NULL;

    SELECT emp_name,post_comment FROM employee 
        WHERE post_comment IS NOT NULL;
        
    SELECT emp_name,post_comment FROM employee 
        WHERE post_comment=''; 注意''是空字符串,不是null
    ps:
        执行
        update employee set post_comment='' where id=2;
        再用上条查看,就会有结果了

#5:关键字IN集合查询
    SELECT emp_name,salary FROM employee 
        WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;
    
    SELECT emp_name,salary FROM employee 
        WHERE salary IN (3000,3500,4000,9000) ;

    SELECT emp_name,salary FROM employee 
        WHERE salary NOT IN (3000,3500,4000,9000) ;

#6:关键字LIKE模糊查询
    通配符’%SELECT * FROM employee 
            WHERE emp_name LIKE 'eg%';

    通配符’_’
    SELECT * FROM employee 
            WHERE emp_name LIKE 'al__';

group by分组

单独使用GROUP BY关键字分组

	SELECT post FROM employee GROUP BY post;

注意:我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数。
GROUP BY关键字和GROUP_CONCAT()函数一起使用:

    SELECT post,GROUP_CONCAT(emp_name) FROM employee GROUP BY post;#按照岗位分组,并查看组内成员名
    SELECT post,GROUP_CONCAT(emp_name) as emp_members FROM employee GROUP BY post;

GROUP BY与聚合函数一起使用

    select post,count(id) as count from employee group by post;#按照岗位分组,并查看每个组有多少人
如果我们用unique的字段作为分组的依据,则每一条记录自成一组,这种分组没有意义
多条记录之间的某个字段值相同,该字段通常用来作为分组的依据

having过滤

having与where不同:

#!!!执行优先级从高到低:where > group by > having 
#1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。
#2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,可以使用聚合函数

order by排序

按单列排序
    SELECT * FROM employee ORDER BY salary;
    SELECT * FROM employee ORDER BY salary ASC;
    SELECT * FROM employee ORDER BY salary DESC;

按多列排序:先按照age排序,如果年纪相同,则按照薪资排序
    SELECT * from employee
        ORDER BY age,
        salary DESC;

limit 限制查询的记录数

示例:
    SELECT * FROM employee ORDER BY salary DESC 
        LIMIT 3;                    #默认初始位置为0 
    
    SELECT * FROM employee ORDER BY salary DESC
        LIMIT 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5条

    SELECT * FROM employee ORDER BY salary DESC
        LIMIT 5,5; #从第5开始,即先查询出第6条,然后包含这一条在内往后查5条

正则表达式

SELECT * FROM employee WHERE emp_name REGEXP '^ale';

SELECT * FROM employee WHERE emp_name REGEXP 'on$';

SELECT * FROM employee WHERE emp_name REGEXP 'm{2}';


小结:对字符串匹配的方式
WHERE emp_name = 'egon';
WHERE emp_name LIKE 'yua%';
WHERE emp_name REGEXP 'on$';

多表连接查询

#重点:外链接语法
SELECT 字段列表
    FROM1 INNER|LEFT|RIGHT JOIN2
    ON1.字段 =2.字段
    where 条件语句;

交叉连接

交叉连接:不适用任何匹配条件。生成笛卡尔积

select * from 表名1,表名2;

内连接 inner join

内连接:只连接匹配的行
找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果。

外链接之左连接left join

优先显示左表全部记录
本质就是:在内连接的基础上增加左边有右边没有的结果

外链接之右连接right join

优先显示右表全部记录
本质就是:在内连接的基础上增加右边有左边没有的结果

子查询

#1:子查询是将一个查询语句嵌套在另一个查询语句中。
#2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
#3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
#4:还可以包含比较运算符:= 、 !=、> 、<等

视图

视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,并可以将其当作表来使用。

#增:
CREATE VIEW 视图名称 AS  SQL语句;
#删:
DROP VIEW 视图名称;
#改:
ALTER VIEW 视图名称 AS SQL语句;
#查:
select * from 视图名称
使用视图时,将其当作表进行操作即可,由于视图是虚拟表,所以无法使用其对真实表进行创建、更新和删除操作,仅能做查询用

触发器

对某个表进行【增/删/改】操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行【增/删/改】前后的行为。

# 插入前
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 插入后
CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 删除前
CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 删除后
CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 更新前
CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 更新后
CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
BEGIN
    ...
END

#插入前触发器示例
delimiter //
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN

IF NEW. NAME == 'alex' THEN
    INSERT INTO tb2 (NAME)
VALUES
    ('aa')
END
END//
delimiter ;

#插入后触发器示例
delimiter //
CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
BEGIN
    IF NEW. num = 666 THEN
        INSERT INTO tb2 (NAME)
        VALUES
            ('666'),
            ('666') ;
    ELSEIF NEW. num = 555 THEN
        INSERT INTO tb2 (NAME)
        VALUES
            ('555'),
            ('555') ;
    END IF;
END//
delimiter ;

#删除触发器
DROP TRIGGER tri_after_insert_tb1;
1.NEW表示即将插入的数据行,OLD表示即将删除的数据行。
2.delimiter申明结束符号。
3.触发器无法由用户直接调用,而知由于对表的【增/删/改】操作被动引发的。

存储过程

存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。

创建存储过程

在这里插入代码片
-- 创建存储过程

delimiter //
create procedure p1()
BEGIN
    select * from t1;
END//
delimiter ;



-- 执行存储过程

call p1()

带参数的存储过程

对于存储过程,可以接收参数,其参数有三类:

  • in 仅用于传入参数用
  • out 仅用于返回值用
  • inout 既可以传入又可以当作返回值
-- 创建存储过程
delimiter \\
create procedure p1(
    in i1 int,
    in i2 int,
    inout i3 int,
    out r1 int
)
BEGIN
    DECLARE temp1 int;
    DECLARE temp2 int default 0;
    
    set temp1 = 1;

    set r1 = i1 + i2 + temp1 + temp2;
    
    set i3 = i3 + 100;

end\\
delimiter ;

-- 执行存储过程
set @t1 =4;
set @t2 = 0;
CALL p1 (1, 2 ,@t1, @t2);
SELECT @t1,@t2;

结果集

 delimiter //
 create procedure p1()
 begin
     select * from v1;
 end //
 delimiter ;

删除存储过程

drop procedure proc_name;

执行存储过程

-- 无参数
call proc_name()

-- 有参数,全in
call proc_name(1,2)

-- 有参数,有in,out,inout
set @t1=0;
set @t2=3;
call proc_name(1,2,@t1,@t2)

函数

MySql中提供了很多内置函数:官方地址

自定义函数

delimiter \\
create function f1(
    i1 int,
    i2 int)
returns int
BEGIN
    declare num int;
    set num = i1 + i2;
    return(num);
END \\
delimiter ;

删除函数

drop function func_name;

执行函数

# 获取返回值
declare @i VARCHAR(32);
select UPPER('alex') into @i;
SELECT @i;


# 在查询中使用
select f1(11,nid) ,name from tb2;

事务

事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

--支持事务的存储过程
delimiter \\
create PROCEDURE p1(
    OUT p_return_code tinyint
)
BEGIN 
  DECLARE exit handler for sqlexception 
  BEGIN 
    -- ERROR 
    set p_return_code = 1; 
    rollback; 
  END; 
 
  DECLARE exit handler for sqlwarning 
  BEGIN 
    -- WARNING 
    set p_return_code = 2; 
    rollback; 
  END; 
 
  START TRANSACTION; 
    DELETE from tb1;
    insert into tb2(name)values('seven');
  COMMIT; 
 
  -- SUCCESS 
  set p_return_code = 0; 
 
  END\\
delimiter ;
--调用
set @i =0;
call p1(@i);
select @i;

索引

索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构。类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获取即可。
MySQL中常见索引有:

  • 普通索引
  • 唯一索引
  • 主键索引
  • 组合索引

普通索引

普通索引仅有一个功能:加速查询

--创建表+索引
create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
)--创建索引
create index index_name on table_name(column_name)--删除索引
drop index_name on table_name;
--查看索引
show index from table_name;
注意:对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。
create index ix_extra on in1(extra(32));

唯一索引

唯一索引有两个功能:加速查询 和 唯一约束(可含null)

--创建表+唯一索引
create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    unique ix_name (name)
);
--创建唯一索引
create unique index 索引名 on 表名(列名);
--删除唯一索引
drop unique index 索引名 on 表名;

主键索引

主键有两个功能:加速查询 和 唯一约束(不可含null)

--创建表+创建主键
create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
);

OR

create table in1(
    nid int not null auto_increment,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    primary key(ni1),
    index ix_name (name)
);
--创建主键
alter table 表名 add primary key(列名);
--删除主键

alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

组合索引

组合索引是将n个列组合成一个索引。
其应用场景为:频繁的同时使用n列来进行查询,如:where n1 = ‘alex’ and n2 = 666。

--创建表
create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
);
--创建组合索引
create index ix_name_email on in3(name,email);

如上创建组合索引之后,查询:

  • name and email – 使用索引
  • name – 使用索引
  • email – 不使用索引
    注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并。

其他

--1.if条件语句
delimiter \\
CREATE PROCEDURE proc_if ()
BEGIN
    
    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END\\
delimiter ;

--2.while循环
delimiter \\
CREATE PROCEDURE proc_while ()
BEGIN

    DECLARE num INT ;
    SET num = 0 ;
    WHILE num < 10 DO
        SELECT
            num ;
        SET num = num + 1 ;
    END WHILE ;

END\\
delimiter ;

--3.repeat循环
delimiter \\
CREATE PROCEDURE proc_repeat ()
BEGIN

    DECLARE i INT ;
    SET i = 0 ;
    repeat
        select i;
        set i = i + 1;
        until i >= 5
    end repeat;

END\\
delimiter ;

--4.loop循环
BEGIN
    declare i int default 0;
    loop_label: loop
        
        set i=i+1;
        if i<8 then
            iterate loop_label;
        end if;
        if i>=10 then
            leave loop_label;
        end if;
        select i;
    end loop loop_label;
END

--5.动态执行SQL语句
delimiter \\
DROP PROCEDURE IF EXISTS proc_sql \\
CREATE PROCEDURE proc_sql ()
BEGIN
    declare p1 int;
    set p1 = 11;
    set @p1 = p1;

    PREPARE prod FROM 'select * from tb2 where nid > ?';
    EXECUTE prod USING @p1;
    DEALLOCATE prepare prod; 

END\\
delimiter ;
发布了32 篇原创文章 · 获赞 32 · 访问量 6813

猜你喜欢

转载自blog.csdn.net/qq_33267875/article/details/97292568