郑统京 发表于 2023-9-16 11:01:37

随笔十八:SQL的其他用法

17、其他SQL用法1、视图(了解)
什么是视图?
"""
视图就是通过查询得到的一张虚拟表,然后保存下来,下次可以直接使用
"""

为什么要用视图?
"""
如果频繁使用一张虚拟表(连表),你就可以制作视图 后续直接操作
"""

如何使用?
# 固定语法
create view 表名 as 虚拟表的查询sql语句
# 具体操作
create view teacher2course as
select course.cid from course inner join teacher on course.teacher_id = teacher.id where tname not in ('李平');
# 注意
"""
    1、创建视图在硬盘上只会有表结构 没有表数据(数据还是来自之前的表)
    2、视图只用来查询,里面的数据不能修改,会影响真正数据报错
"""

视图使用频率高不高?
"""
不高
当表创建多的时候,会造成表的错乱,不好维护
"""2、触发器(了解)在满足对表数据的增、删、改的情况下,自动触发的功能,为什么没有查呢?因为查不具有危险性使用触发器可以帮助我们实现监控、日志、自动处理异常等...触发器可以在6种情况下自动触发增前、增后、改前、改后、删前、删后
# 基本语法结构
create trigger 触发器的名字 before/after insert/update/deleteon 表名
for each now
begin
    sql语句
end

# 具体使用 针对触发器的名字 我们通常需要做到见明字意
# 增加之前触发的
create trigger tri_before_insert_t1 before insert on t1
for each now
begin
    sql语句
end

# 更新之前触发的
create trigger tri_before_update_t1 before update on t1
for each now
begin
    sql语句
end
...循环往复删除也是

ps:修改MySQL默认的结束符 只作用于当前窗口
    delimiter $$ =>默认分号的结束符变成$$

"""
当cmd表种的记录success字段是no那么就触发触发器的执行errlog表中插入数据
New指代的是一条条数据对象
"""
delimiter $$# 修改结束符,否则一到 ;就会结束无法导致触发器生效
create trigger tri_after_insert_cmd after insert on cmd
for each row
begin
    if New.success ='no' then
      insert into errlog(err_cmd,err_time)
    values(New.dmd,New.sub_time);
    end if;
end $$
delimiter ; # 最后在把结束符换成;

# 实战演示触发器
CREATE TABLE cmd (
    id INT PRIMARY KEY auto_increment,
    USER CHAR (32),
    priv CHAR (10),
    cmd CHAR (64),
    sub_time datetime, #提交时间
    success enum ('yes', 'no') #0代表执行失败
);

CREATE TABLE errlog (
    id INT PRIMARY KEY auto_increment,
    err_cmd CHAR (64),
    err_time datetime
);
# 朝cmd表插入数据
INSERT INTO cmd (
    USER,
    priv,
    cmd,
    sub_time,
    success
)
VALUES
    ('jason','0755','ls -l /etc',NOW(),'yes'),
    ('jason','0755','cat /etc/passwd',NOW(),'no'),
    ('jason','0755','useradd xxx',NOW(),'no'),
    ('jason','0755','ps aux',NOW(),'yes');
# 结果
errlog=》有两条success是no的数据

# 删除触发器
droptrigger tri_after_insert_cmd

​3、事务
[*]什么是事务
"""
开启事务可以包含多条sql语句 这些sql语句要么同时成功
要么同时失败,称之为事务的原子姓
"""
- 事务的作用```python"""保证了数据操作的安全性"""eg:还钱的例子      egon用银行卡转给我的1000块      1、将egon银行账户的数据减少1000      2、将jason支付宝的数据增加1000在操作多条数据的时候可能会出现某几条操作不成功的情况


[*]事务的四大特性
"""
ACID
A:原子性
    一个事务是一个不可分割的单位,事务中包含的诸多操作
    要么同时成功要么同时失败
C:一致性
    事务必须是使用数据从一个一致性的状态变到另外一个一致性的状态
    一致性和原子性密切相关
I:隔离性
    一个事务的执行不能被其他事务干扰,即一个事务内部的操作使用到的数据对并发的其他事务是互不干扰的(进程间数据不会被干扰)
D:持久性
    也叫'永久性'
    一个事务一旦提交执行成功 那么他对数据库种数据的修改应该是永久的
    接下来的其他操作或者故障不应该对其有任何影响,类似pymysql增删改的时候没有提交时候在内存中,提交之后才会到硬盘
"""​
[*]如何使用事务
# 事务相关的关键字
# 1、开启事务
start transation;
# 2、回滚(回到事务执行之前的状态)
rollback
# 3、确认(确认之后无法回滚)
commit

"""
模拟转账功能
"""
create table user(
    id int primary key auto_increment,
      name char(16),
      balance int
);
insert into user(name,balance) values
('jason',1000),
('egon',1000),
('tank',1000);

# 1、开启事务
start transation;
# 2、多条sql语句
update user set balace=900 where name ='jason';
update user set balace=1010 where name ='egon';
update user set balace=1090 where name ='tank';
# 3、如果不想执行
rollback;
# 4、确认执行
commit;
​​
[*]总结
"""
总结:
    当年你想让多条sql同时成功的时候,你就可以使用事务
    要么同时成功,要么同时失败
"""
4、存储过程(了解)
"""
存储过程就类似与python中的自定义函数
他的内部包含了一系列的可执行的sql语句,存储过程就存放在MySQL客户你,可以通过待用存储过程
触发内部sql语句执行
"""
# 基本使用
create procedure 存储过程的名字(形参1,形参2...)
begin
    sql代码
end
# 调用
call 存储过程名字()三种开发模式第一种 (不用)
"""
应用程序:程序员写代码开发
MySQL:提前编写好存储过程,供应用程序调用

好处:开发效率提升了 执行效率也提升了
坏处:考虑到人为元素、跨部门沟通成本问题,后续存储过程的拓展性差
"""第二种 (有时)
"""
应用程序:程序员写代码开发之外 涉及到数据库操作也自己动手写
优点:扩展性高
缺点:
    开发效率降低
    编写sql语句太过繁琐,后续还需要考虑sql优化问题
"""第三种 (常用)
"""
应用程序:只写程序代码 不写sql语句 基于别人写好的操作MySQL的python框架直接操作即可 ORM框架
优点:开发效率比上面两种都要高
缺点:语句的扩展性差,可能会出现效率低下的问题

"""存储过程演示
delimiter $$
create procedure p1(
    in m int, # 只进不出m不能返回出去
    in n int,
    out res int, # 该形参可以返回出去
)
begin
    select tnam from teacher where tid>m and tid<n;
    set res =666 # 用来标识当前存储过程代码确实执行了
end $$
delimiter ;

# 针对形参res 不能直接传数据 应该传一个变量
# 定义变量
set @ret=10
# 查看变量对应的只
select @ret
​在原生的pymysql如何调用呢?
import pymysql


conn = pymysql.connect(
      host = '127.0.0.1',
      port = 3306,
      user = 'root',
      passwd = '123456',
      db = 'day48',
      charset = 'utf8',
      autocommit = True
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 调用存储过程
cursor.callproc('p1',(1,5,10))
"""
@_p1_0=1
@_p1_1=5
@_p1_2=10
"""
# print(cursor.fetchall())
cursor.execute('select @_p1_2;')
print(cursor.fetchall())5、函数跟存储过程有区别的是,存储过程是一个自定义函数,而函数是内置的now()获取当前时间 date_format() 时间格式化
# 示例
('jason','0755','ls -l /etc',NOW(),'yes')

CREATE TABLE blog (
      id INT PRIMARY KEY auto_increment,
      NAME CHAR (32),
      sub_time datetime
);

INSERT INTO blog (NAME, sub_time)
VALUES
      ('第1篇','2015-03-01 11:31:21'),
      ('第2篇','2015-03-11 16:31:21'),
      ('第3篇','2016-07-01 10:21:31'),
      ('第4篇','2016-07-22 09:23:21'),
      ('第5篇','2016-07-23 10:11:11'),
      ('第6篇','2016-07-25 11:21:31'),
      ('第7篇','2017-03-01 15:33:21'),
      ('第8篇','2017-03-01 17:32:21'),
      ('第9篇','2017-03-01 18:31:21');

select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');=》结果和博客园的文章一样,2021年9月(4篇)6、流程控制(了解)
# 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 ;
# 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 ;7、索引ps:数据都是存在硬盘上的,查询数据不可避免的需要进行IO操作索引:就是一种数据结构,类似于书的目录。意味着以后在查询数据的时候应该先找目录再找数据,而不是一页一页的翻书,从而提升速度降低IO操作索引在MySQL种也叫键,是存储引擎用于快速查询记录的一种数据结果
[*]primary key
[*]unique key
[*]index key
注意foreign key不是用来加速查询用的,不在我们的研究范围内上面的三种key,前面两种除了增加查询速度之后各自还具有约束条件,而最后一种index key没有任何的约束条件,只是用来帮你快速查询数据本质通过不断的缩小想要的数据范围筛选出最终的结果,同时将随机事件(一页一页的翻)变成顺序事件(先找目录,再找数据)也就是说有了索引机制,我们可以总是用一种固定方式查询数据一张表中可以有多个索引(多个目录)索引虽然能够帮助你加快查询速度但是也有缺点
"""
1、当表中有大量数据存在时,创建索引会非常慢
2、在索引创建完毕之后,对表的查询性能会大幅提升,但是写的性能也会大幅度降低,(例如给一个表中添加新的字段,会把之前的索引打乱,重新加索引)
"""
索引不要随意的创建1、B+树
"""
只有叶子节点存放的是真实数据,其他节点存放虚拟数据用来指路
树的层级越高,查询数据所经历的不走就越多(树有几层,查询步骤就需要几步)

一个磁盘块存储是有限制的
为什么建议你将id字段作为主键(索引)?
    因为主键是id的占的空间少,可以存放更多的目录,这样的B+树的高度,减少查询步骤
"""2、聚集索引(primary key)
"""
聚集索引指的就是主键
Innodb 只有两个文件,直接将主键存放在idb数据表中
myIsam 三个文件 单独将索引存在一个文件
"""3、辅助索引(unique,index)
"""
查询数据的时候,不可能一直使用到主键,也有可能用到name,password等其他字段那么这个时候没有办法利用聚集索引,
这个时候你就可以根据情况给其他字段设置辅助索引

辅助索引(也是一个B+树)
    叶子节点存放的是数据对应的主键值
    先按照辅助索引拿到数据的主键值
    之后还是需要取主键的聚集索引里面查询数据
"""4、覆盖索引
"""
在辅助索引的叶子节点就已经拿到了需要的数据
"""
# 给name设置辅助索引,name中可以直接获取到想要的数据了,这种情况就是覆盖索引
select name from user where name ="jason";
# 非覆盖索引,name是辅助索引,但是需要age
select age from user where name ="jason";








页: [1]
查看完整版本: 随笔十八:SQL的其他用法