暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL必知必会笔记(4)

CoderGeshu 2020-04-14
187

 Life is never fair, and perhaps it is a good thing for most of us that it is not.


【前文链接】

MySQL必知必会笔记(1)

MySQL必知必会笔记(2)——函数集合

MySQL必知必会笔记(3)

12. 增删改查

12.1 插入数据

  1. 插入的方式
  • 插入完整的行
  • 插入行的一部分
  • 插入多行
  • 插入某些查询的结果

插入完整的行,不安全,如下:

insert into tbl_name values(v1, v2, ...);

复制

编写insert语句的更安全的方法:将列名标出来,如下:

insert into customers(col1, col2, ...) values(v1, v2, ...);

复制

如果表的定义允许,则可以在insert操作中省略某些列。省略的列必须满足以下某个条件:

  • 该列定义为允许NULL值
  • 在表定义中给出默认值。

如果对表中不允许null且没有默认值的列不给出值,则mysql将报错。

提高整体性能

数据库经常被多个客户访问,insert会很耗时,而且可能降低等待处理的select语句的性能。如果数据检索是重要的,可以通过在insert和into之间添加关键字LOW_PRIORITY
,指示mysql降低insert语句的优先级。如下:

INSERT LOW_PRIORITY INTO ...

复制

另外,LOW_PRORITY也适用于UPDATE和DELETE语句

  1. 插入多行

values后面直接跟多组数据,数据间用逗号隔开

insert into customers(col1, col2, ...) values(v1, v2, ...),
(v3, v4, ...),
(v5, v6, ...);

复制
  1. 插入检索出来的数据

利用insert将一条select语句的结果插入表中,即所谓的insert select语句。由一条insert和一条select语句组成,如下:

INSERT INTO customers(col1, col2, ...)
SELECT col1, col2, ...
FROM tbl_name
WHERE ...

复制

12.2 更新数据(注意使用安全)

  1. 更新方式
  • 更新特定行(一定要where,where一定要正确筛选到)
  • 更新所有行
  1. 删除某个列

UPDATE还用于删除某个的值,即清空某一列的值,使用UPDATE而不是DELETE,如下:

UPDATE tbl_name
SET col = NULL
WHERE ...

复制
  1. IGNORE关键字

如果用UPDATE语句更新多行,并且在其中一行出错,则会回退取消整个UPDATE操作,如果要求即使发生错误也继续进行更新,可使用IGNORE关键字,如下:

UPDATE IGNORE tbl_name ...

复制

12.3 删除数据(注意使用安全)

  1. 删除方式
  • 删除特定行(一定要where,where一定要正确筛选到)
  • 删除所有行
  1. 更快的删除

如果想删除表中所有的行,可使用TRUNCATE TABLE
语句,它完成删除表格相同的工作,但速度更快(删除原来的并重新建一个表,而不是逐行删除表中的数据)。

重要

为了保证UPDATE和DELETE操作不误伤(没有where或者where的效果不同于预期):

  1. 先测试WHERE子句对不对,确保它过滤的是正确的记录;
  2. 使用强制实施引用完整性的数据库,这样与其他表有关联的行也不能被删除。

13. 视图

视图是虚拟的表,是几个表联查询的动态结果。 视图不存储数据,每次查看视图时,要重新执行查询表语句,因此大型、复杂视图性能低。

13.1 为何使用视图

  • 重用SQL语句,简化复杂查询,不必重复编写查询联结细节;
  • 保护数据,可以给用户授权只能访问表的一部分数据;
  • 更改数据格式和表示,与底表可以不同。

13.2 视图的规则与限制

  • 视图名字必须唯一;
  • 视图数目无限制;
  • 创建视图需要有相应表的访问权限;
  • 视图可以嵌套,即联结其他视图来创建新视图;
  • 视图中order by作用,会被基表中的order by覆盖;
  • 视图不能有索引、触发器、默认值;
  • 视图可以和表一起使用,即连接查询。

13.3 使用视图

  1. 创建视图
CREATE VIEW view_name AS SELECT ...

复制
  1. 查看创建视图的语句
SHOW CREATE VIEW view_name;

复制
  1. 删除视图
DROP VIEW view_name;

复制

如果指定的视图不存在,则DROP VIEW将产生一个错误。可以使用如下语句防止产生错误:

DROP VIEW IF EXISTS view_name;

复制
  1. 更新视图
  • 先删除视图,再重新创建;
  • 使用create or replace view view_name
    ,如果视图不存在就创建,视图存在就替换。

如果视图定义中有以下操作,则不能进行视图更新:

  • 分组(GROUP BY、HAVING);
  • 联结;
  • 子查询;
  • 并查询(组合查询UNION);
  • 聚集函数;
  • 唯一值(DISTINCT);
  • 计算列。

注意:一般应将视图用于检索,而非更新。对视图的增、删、改,实际是对底表数据进行操作。

14. 存储过程

存储过程,简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。

可将其视为批文件,虽然他们的作用不仅限于批处理。

14.1 优缺点

  • 优点

    • 执行效率非常快!存储过程是在数据库的服务器端执行

    • 简化复杂操作。因为把处理封装在容易使用的单元中;

    • 保证了数据的完整性。不要求反复建立一系列处理步骤(防止错误);

    • 简化对变动的管理。如果表名、列名或业务逻辑有变化,只需要修改存储过程的代码。使用它的人员甚至不需要知道这些变化(减少了数据讹误,确保了安全性);

    • 提高性能。存储过程比单独的SQL语句要快;

    • 代码更强更灵活。存在一些只能用在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。

  • 缺点

    • 存储过程比SQL语句复杂得多;
    • 移植性很差,不同的数据库的存储过程是不能移植的;
    • 并不是所有人都有创建存储过程的安全访问权限。

14.2 创建存储过程

CREATE PROCEDURE proc_name([[IN|INOUT|OUT] param_name TYPE|...])
BEGIN
SELECT ...
FROM tbl_name;
END;

复制

注意

(1)BEGIN
END
用来限定存储过程体。

(2)默认的MySQL分隔符为;
,但是存储过程中包含有;
,这会使存储过程中的SQL语句出现句法错误。解决办法就是临时更改命令行实用程序的语句分隔符:

DELIMITER $
CREATE PROCEDURE proc_name([ [IN|INOUT|OUT] param_name TYPE| ... ])
BEGIN
SELECT ...
FROM tbl_name;
END $
DELIMITER ;

复制

DELEMITER $
 告诉实用程序实用$
作为新的语句结束分隔符,可以看到标志存储过程结束的END定义为END $
。这样存储体内的;
可以保持不变,正确地传递给引擎,最后再恢复为原来的语句分隔符;
。除了\
之外都可定义为分隔符,\
一般用为转义符。

(3)没有参数的存储过程也不能省略()
,它就相当于一个空参的函数,调用时也要遵守这一原则。

(4)如果有参数,要明确参数类型:数据类型和输入输出类型(IN/OUT/INOUT
):

  • OUT
    :指出相应的参数用来从存储过程传出一个值,返回给调用者;
  • IN
    :传递给存储过程;
  • INOUT
    :对存储过程传入和传出。

如下代码所示:

DELIMITER $
CREATE PRODUCER proc_name(IN param1 INT, OUT param2 DECIMAL(8, 2))
BEGIN
SELECT Min(col_name)
FROM tbl_name
WHERE id = param1
INTO param2;
END $
DELIMITER ;

复制

注意:IN类型参数和OUT类型参数的位置。

14.3 查看存储过程

(1)SHOW PROCEDURE STATUS
列出所有存储过程,为了限制其显示某些特定的存储过程,可以用LIKE关键字指定一个过滤模式:

SHOW PROCEDURE STATUS LIKE 'proc_name'

复制

(2)如果要获得存储过程的详细信息,可以使用SHOW语句进行显示:

SHOW CREATE PROCEDURE proc_name; -- 只给出存储过程名字

复制

注意:此时只给出存储过程名字即可,不再加()

14.4 执行存储过程

MySQL中使用关键字CALL
来执行存储过程,CALL
接收存储过程的名字以及需要传递给它的任意参数(变量)

变量是内存中一个特定的位置,用来临时存储数据。

所有MySQL的变量都必须以@
开始。

针对上述的带参存储过程,执行语句如下:

CALL proc_name(1001, @result);

复制

其中的1001
是传入给存储过程,变量@result
是由存储过程传出的值。

一般情况下,带有输出变量的存储过程执行后并不显示结果,而是把结果返回给你指定的变量(如上述的@result),若要显示结果,则需另外执行SELECT语句显示返回结果,如下:

SELECT @result;

复制

14.5 删除存储过程

DROP PROCEDURE proc_name;

复制

此时仍然只给出存储过程名字即可,不再加()
。如果指定的存储过程不存在,则DROP PROCEDURE将产生一个错误。可以使用如下语句防止产生错误:

DROP PROCEDURE IF EXISTS proc_name;

复制

14.6 建立复杂存储过程

复杂存储过程可能用到的关键字:

  • -- :注释

  • DECLARE:定义局部变量。形式如:DECLARE variable_name TYPE
    ; 变量名前不用加@符号

  • IF:条件语句,还支持ELSEIF(使用THEN), ELSE(不使用THEN)语句

  • COMMENT:不是必需的,但是如果给出,将在SHOW PROCEDURE STATUS
    的结果中显示,

一个实例:

考虑这个场景:有一个订单表需要获得订单合计,但需要对合计增加营业税,不过只针对某些客户。

根据场景列出存储过程中应执行的事件:

  1. 获得合计;
  2. 把营业税有条件地添加到合计;
  3. 返回合计(带税或不带税)。

源代码如下:

-- Name:ordertotal
-- Parameters:onumber = order number
-- taxable = 0 if not taxable, 1 if taxable
-- ototal = order total variable

DELIMITER $
CREATE PROCEDURE ordertotal(IN onumber INT, IN taxable BOOLEAN,OUT ototal DECIMAL(8, 2))
COMMIT "obtain order total, optionally adding tex"
BEGIN
-- Declare variable for total
DECLARE total DECIMAL(8, 2);
-- Declare tax percentage
DECLARE taxrate INT DEFAULT 6;

-- Get the order total
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;

-- Is it taxable?
IF taxable THEN
-- Yes, so add taxrate to the total
SELECT total+(total/100*taxrate) INTO total;
END IF;
-- And finally, save to out variable
SELECT total INTO ototal;
END $
DELIMITER ;

复制

执行存储过程并显示结果:

CALL orderototal(20005, 0, @total);
SELECT @total;

复制

15. 触发器

MySQL中的触发器概念,和Java中的事件监听器有点相似。当你想要某条语句在某个事件发生时自动执行,就要用到触发器了。

触发器能响应如下三类语句:DELETE、INSERT和UPDATE。

15.1 创建触发器

创建须知

  • 只有表才支持触发器,视图不支持,临时表也不支持;
  • 每个表的每个事件每次只允许一个触发器;
  • 每个表最多支持6个触发器(即每个INSERT、UPDATE和DELETE可以选择使用BEFORE或AFTER修饰);
  • 单一触发器不能与多个事件或多个表关联,所以如果需要一个对INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。

创建触发器时,需要给出4条信息:

  1. 唯一的触发器名
  2. 触发器关联的表
  3. 触发器应该响应的活动(DELETE、INSERT、UPDATE)
  4. 触发器何时执行(处理之前或之后)

创建代码如下:

CREATE TRIGGER tri_name
AFTER INSERT ON tbl_name FOR EACH ROW
SELECT 'insert success';

复制

分析:

CREATE TRIGGER用来创建名为tri_name的新触发器。触发器可在一个操作发生之前或之后执行,这里给出了AFTER INSERT,所以此触发器将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本“insert success”将对每个插入的行显示一次。

15.2 INSERT触发器

INSERT触发器在INSERT语句执行之前或之后执行 :

  • 在INSERT触发器代码内,可引用一个名为NEW
    的虚拟表,访问被插入的行;
  • 在BEFORE INSERT触发器中,NEW
    的值也可以被更新(允许更改被插入的值);
  • 对于AUTO_INCREMENT列,NEW
    在INSERT执行前包含0,在INSERT被执行后包含新的自动生成值。

如下代码:

CREATE TRIGGER tri_name
AFTER INSERT ON tbl_name FOR EACH ROW
SELECT NEW.col_name INTO @vari;

复制

分析:

此代码创建一个名为tri_name的触发器,在插入新信息到tbl_name表并成功后,插入信息会保存在NEW
表中,触发器从NEW
表中取得col_name的值并赋给变量@vari
,因为从MySQL 5以后不支持触发器返回结果集,可以执行SELECT @vari
来显示它的值。

注意

  • 使用BEFORE还是AFTER:通常,将BEFORE用于对NEW表进行数据验证和净化(目的是保证插入表中的数据确实是需要的数据),此条也适用于UPDATE触发器。
  • 触发器失败:如果BEFORE触发器失败,则MySQL将不执行请求的操作。此外,如果BEFORE触发器或语句本身失败,MySQL将不执行AFTER触发器(如果有的话)。

15.3 DELETE触发器

DELETE触发器在DELETE语句执行之前或之后执行:

  • 在DELETE触发器代码内,可以引用一个名为OLD
    的虚拟表,访问被删除的行;
  • OLD
    中的值全部都是只能读的,不能更新

如下代码:

DELIMITER $
CREATE TRIGGER tri_name
BEFORE DELETE ON tbl_name FOR EACH ROW
BEGIN
INSERT INTO archive_table(id, name, age) VALUES(OLD.id, OLD.name, OLD.age);
END $
DELIMITER ;

复制

分析:

在任意订单被删除将执行此触发器。它使用一条INSERT语句将OLD中的值(要被删除的订单信息)保存到一个名为archive_table的存档表中(为实际使用这个例子,你需要建立一个和被删除信息表具有相同结构的archive_table表)。

★相对于AFTER DELETE触发器来说,使用BEFORE DELETE触发器的优点为:如果由于某种原因,订单不能存档,那么DELETE本身将被放弃,也即不再执行DELETE操作。

使用BEGIN END块的好处是触发器能容纳多条SQL语句。

15.4 UPDATE触发器

UPDATE触发器在UPDATE语句执行之前或之后执行:

  • 在UPDATE触发器代码中,对于更新前的旧值,可以引用OLD
    虚拟表访问;对于新值,可以引用NEW
    虚拟表访问;
  • 在BEFORE UPDATE触发器中,NEW
    中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
  • OLD
    中的值全都是只读的,不能更新。

代码如下:

CREATE TRIGGER tri_name
BEFORE UPDATE ON tbl_name FOR EACH ROW
SET NEW.name = Upper(NEW.name);

复制

分析:此代码表示在执行更新前,把将要插入的数据中的name值全部转换为大写,以此来净化插入数据。

15.5 删除触发器

DROP TRIGGER [if exists] tri_name;

复制

注意:触发器不能更新或覆盖。为了修改一个触发器,必须先删除它,然后再重新创建。

15.6 触发器进一步介绍

  • 与其他DBMS相比,MySQL 5中支持的触发器相当初级。未来的MySQL版本中有一些改进和增强触发器支持的计划。
  • 创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果INSERT、UPDATE或DELETE语句能够执行,则相关的触发器也能执行。
  • 应该用触发器来保证数据的一致性(大小写、格式等)。在触发器 中执行这种类型的处理的优点是它总是进行这种处理,而且是透明地进行,与客户机应用无关。
  • 触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,把更改(如果需要,甚至还有之前和之后的状态)记录到另一个表非常容易。
  • 遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。


👉MySQL必知必会笔记(3)

👉MySQL必知必会笔记(2)——函数集合

👉MySQL必知必会笔记(1)

👉Java代码块与代码加载顺序

👉MoreAboutMe


✨喜欢的老铁动动手指点个关注吧✨



点击『在看』是对我最大的支持  

文章转载自CoderGeshu,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论