赞
踩
MySQL全家桶
视图:是一个虚拟的表,其内容由查询定义。同真实表一样,视图包含一系列带有名称的列和行的数据
视图是虚拟表,本身不存储数据,而是按照指定的方式进行查询
操作指令 | 代码 |
---|---|
创建视图 | CREATE VIEW 视图名(列1,列2...) AS SELECT (列1,列2...) FROM ...; |
使用视图 | 当成表使用就好 |
修改视图(1) | CREATE OR REPLACE VIEW 视图名 AS SELECT [...] FROM [...]; |
修改视图(2) | ALTER VIEW 视图名 AS SELECT [...] FROM [...]; |
查看数据库已有视图 | >SHOW TABLES [like...]; (可以使用模糊查找) |
查看视图详情 | DESC 视图名 或者SHOW FIELDS FROM 视图名 |
视图条件限制 | [WITH CHECK OPTION] |
# 语法
CREATE VIEW 视图名(列1,列2...) as sql查询语句
查询person表中 所有内容 作为p_1的视图
create view v_1 as select * from person
# 语法
ALTER OR REPLACE [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
create or replace view v_1 as select id,name,age,salary from person
# 语法
ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
alter view v_1 as select id,name,age,salary from person
create or replace view 和 create view 的区别
create or replace view的意思就是若数据库中已经存在这个名字的视图的话,就替代它,若没有则创建视图;
create则不进行判断,若数据库中已经存在的话,则报错,说对象已存在;
# 语法
select *|列明 from 视图名称;
查询p_1视图中所有信息
select * from v_1
SHOW TABLES;
通过show tables;
反馈得到所有的表和视图。同样的,我们可以通过模糊检索的方式专门查看视图,这个时候,视图的命令统一采用v_视图名的优势就体现出来了。
# 语法
desc 视图名
desc v_1
# 语法
show fields from 视图名
show fields from v_1
insert into v_1 values('14','Charm','18','男','2333.00','2010-06-21', '1')
跨表插入数据系统反馈报错,提示不能修改超过一个表的数据。
因此,可以通过视图插入数据,但是只能基于一个基础表进行插入,不能跨表更新数据
如果在创建视图的时候制定了“WITH CHECK OPTION”,那么更新数据时不能插入或更新不符合视图限制条件的记录。
with check option可以这么解释:通过视图进行的修改,必须也能通过该视图看到修改后的结果。比如你insert,那么加的这条记录在刷新视图后必须可以看到;如果修改,修改完的结果也必须能通过该视图看到;如果删除,当然只能删除视图里有显示的记录。
# 语法
drop view 视图名
drop view p_1
触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性。
简而言之:触发器——监视某种情况,并触发某种操作。
# 语法
DELIMITER //
create trigger 触发器名 after/before 触发事件(insert/update/delete)
on 表名 for each row #这句话是固定的
begin
#需要执行的sql语句
# 其中,BEGIN与END之间的执行语句列表参数表示需要执行的多个语句,不同语句用分号隔开
end //
DELIMITER ;
# 注意1:after/before: 只能选一个 ,after 表示 后置触发, before 表示前置触发
# 注意2:insert/update/delete:只能选一个
触发器类型 |
INSERT型触发器 |
UPDATE型触发器 |
DELETE型触发器 |
一些语句解释:
一般情况下,mysql默认是以 ; 作为结束执行语句,与触发器中需要的分行起冲突
为解决此问题可用DELIMITER,如:DELIMITER //,可以将结束符号变成//
当触发器创建完成后,可以用DELIMITER ;来将结束符号变成;
#商品表
create table goods(
id int primary key auto_increment, # 商品id
name varchar(20), # 商品名称
num int # 商品数量
);
#订单表
create table order_table(
oid int primary key auto_increment, # 订单id
gid int, # 订单中商品id
much int # 订单数量
);
# 插入3条准备数据
insert into goods(name,num) values('商品1',10),('商品2',10),('商品3',10);

当用户提交一个订单后,我们应修改商品的数量
delimiter //
create trigger t_1 after insert on order_table
for each ROW
BEGIN
update goods set num = num - new.much where id = new.gid;
END//
delimiter ;
对于insert而言,新插入的行用new来表示,行中的每一列的值用new.列名来表示。
当用户修改一个订单的数量时,应修改商品的数量
delimiter //
create trigger t_2 after update on order_table
for each ROW
BEGIN
update goods set num = num + old.much - new.much where id=old.gid;
END//
delimiter ;
当用户撤销一个订单的时候, 应修改商品数量
delimiter //
create trigger t_3 after delete on order_table
for each row
begin
update goods set num = num+old.much where id=old.gid;
end //
delimiter ;
用old来表示旧表中的值,old.列名可以引用原(旧)表中的值。
用old来表示旧表中的值,old.列名可以引用原(旧)表中的值。
触发器无法由用户直接调用,而知由于对表的【增/删/改】操作被动引发的
# 语法
drop trigger 触发器名
drop trigger t_1;
drop trigger t_2;
drop trigger t_3;
MySQL数据库在5.0版本后开始支持存储过程
存储过程:类似于函数(方法),简单的说存储过程是为了完成某个数据库中的特定功能而编写的语句集合,该语句集包括SQL语句(对数据的增删改查)、条件语句和循环语句等。
show procedure status;
# 语法
drop procedure 存储过程名称
drop procedure p1;
# 语法
call 存储过程名称([参数入/出类型 参数名 数据类型]);
DELIMITER // 声明语句结束符,用于区分;
CEATE PROCEDURE demo_in_parameter(IN p_in int) 声明存储过程
BEGIN …. END 存储过程开始和结束符号
SET @p_in=1 变量赋值
DECLARE l_int int unsigned default 4000000; 变量定义
delimiter //
create procedure p1()
BEGIN
select * from person;
END//
delimiter ;
# 在mysql中调用
call p1()
# 在python中基于pymysql调用
cursor.callproc('p1')
print(cursor.fetchall())
对于存储过程,可以接收参数,其参数有三类:
#in 仅用于传入参数用
#out 仅用于返回值用
#inout 既可以传入又可以当作返回值
# 乱入!!!
# into 关键字 可以 将前面字段的查询结果 执行 给 into 后面的变量
# declare 关键字 可以定义变量
delimiter //
create procedure p1(in i_id int)
begin
select * from person where id=i_id;
end//
delimiter ;
call p1(5)
delimiter//
create procedure p1(in i_id int, out counts int)
begin
select count(name) into counts from person where id>i_id;
end//
delimiter;
set @counts=0
call p1(10,@counts)
select @counts
delimiter//
create procedure p1(inout i_id int)
begin
declare nub int default 0;
select count(id) into nub from person where id=i_id;
if nub!=0 then
set i_id=1
else
set i_id=0;
end if;
end//
delimiter;
set @count=5;
call p1(@count);
select @count;
如果输入x>5则返回id大于5的数据的数量,否则返回id小于x的数量
delimiter \\
create procedure p1(in x int, out y int)
begin
if x>=5 then
select count(id) into y from person where id>x;
else
select count(id) into y from person where id<x;
end if;
end\\
delimiter;
set @y=0;
call(10,@y);
select @y;
delimiter\\
create procedure p1(inout x int)
begin
declare sum int default 0;
declare i int default 0;
while i <= x do
set sum = sum+i;
set i = i+1;
set x = sum
end\\
delimiter;
set @nub=100
call(@nub)
select @nub
repeat 也是循环 不过需要注意几点:
repeat..until…end repeat
delimiter\\
create procedure p1(inout x int)
begin
declare sum int default 0;
declare i int default 0;
repeat
set sum = sum+i;
set i = i+1;
until i > x
end repeat;
set x = sum;
end\\
delimiter;
set @nub=100
call p1(@nub)
select @nub

LOOP……END LOOP
loop也是循环
注意:
delimiter\\
create procedure p1(inout x int)
begin
declare sum int default 0;
declare i int default 0;
loop_lable:loop
set sum = sum+i;
set i = i+1;
if i > x then
leave loop_lable;
end if;
end loop;
set x = sum;
end\\
delimiter;
set @count=100;
call p1(@count);
select @count;

MySQL :存储过程
程序 :调用存储过程
MySQL :
程序 :纯SQL语句
MySQL :
程序 :类和对象,即ORM(本质还是纯SQL语句)
Mysql提供了许多内置函数
ROUND(x,y) # 返回参数x的四舍五入的有y位小数的值
RAND() # 返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。
AVG(col) # 返回指定列的平均值
COUNT(col) # 返回指定列中非NULL值的个数
MIN(col) # 返回指定列的最小值
MAX(col) # 返回指定列的最大值
SUM(col) # 返回指定列的所有值之和
GROUP_CONCAT(col) # 返回由属于一组的列值连接组合而成的结果
CHAR_LENGTH(str)
# 返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
CONCAT(str1,str2,...)
# 字符串拼接 如有任何一个参数为NULL ,则返回值为 NULL。
CONCAT_WS(separator,str1,str2,...)
# 字符串拼接(自定义连接符) CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。
FORMAT(X,D)
# 将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。
例如:
SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
INSERT(str,pos,len,newstr)
# 在str的指定位置插入字符串
# pos:要替换位置其实位置
# len:替换的长度
# newstr:新字符串
例如:
SELECT INSERT('abcd',1,2,'tt'); 结果为: 'ttcd'
SELECT INSERT('abcd',1,4,'tt'); 结果为: 'tt'
特别的:
如果pos超过原字符串长度,则返回原字符串
如果len超过原字符串长度,则由新字符串完全替换
INSTR(str,substr)
# 返回字符串 str 中子字符串的第一个出现位置。
LEFT(str,len)
# 返回字符串str 从开始的len位置的子序列字符。
例如:
SELECT INSTR('abc','c'); 结果为: 3
SELECT INSTR('abc','d'); 结果为: 0
LOWER(str) # 变小写
UPPER(str) # 变大写
REVERSE(str)
# 返回字符串 str ,顺序和字符顺序相反。
例如:
SELECT REVERSE('1234567') 结果为:7654321
SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
# 不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。
mysql> SELECT SUBSTRING('Quadratically',5); -- 从第5位开始截取
-> 'ratically'
mysql> SELECT SUBSTRING('foobarbar' FROM 4); -- 从第4位开始截取
-> 'barbar'
mysql> SELECT SUBSTRING('Quadratically',5,6); -- 从第5位开始截取,截取6个长度
-> 'ratica'
mysql> SELECT SUBSTRING('Sakila', -3); -- 从倒数第3位开始截取
-> 'ila'
mysql> SELECT SUBSTRING('Sakila', -5, 3); -- 从倒数第5位开始截取,截取3个长度
-> 'aki'

CURDATE()或CURRENT_DATE() # 返回当前的日期
CURTIME()或CURRENT_TIME() # 返回当前的时间
DAYOFWEEK(date) # 返回date所代表的一星期中的第几天(1~7)
DAYOFMONTH(date) # 返回date是一个月的第几天(1~31)
DAYOFYEAR(date) # 返回date是一年的第几天(1~366)
DAYNAME(date) # 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt) # 根据指定的fmt格式,格式化UNIX时间戳ts
HOUR(time) # 返回time的小时值(0~23)
MINUTE(time) # 返回time的分钟值(0~59)
MONTH(date) # 返回date的月份值(1~12)
MONTHNAME(date) # 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW() # 返回当前的日期和时间
QUARTER(date) # 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
WEEK(date) # 返回日期date为一年中第几周(0~53)
YEAR(date) # 返回日期date的年份(1000~9999)
重点:
DATE_FORMAT(date,format) 根据format字符串格式化date值
mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
-> 'Sunday October 2009'
mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
-> '22:23:00'
mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
-> '%D %y %a %d %m %b %j');
-> '4th 00 Thu 04 10 Oct 277'
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
-> '%H %k %I %r %T %S %w');
-> '22 22 10 10:23:00 PM 22:23:00 00 6'
mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
-> '1998 52'
mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
-> '00'

MD5()
计算字符串str的MD5校验,这个加密过程是不可逆转的
例如:
SELECT MD5('1234') # 结果为:81dc9bdb52d04dc20036dbd8313ed055
PASSWORD(str)
返回字符串str的加密版本,这个加密过程是不可逆转的
例如:
SELECT PASSWORD('1234') # 结果为:*A4B6157319038724E3560894F7F932C8886EBFCF
CASE WHEN[test1] THEN [result1]...ELSE [default] END
如果testN是真,则返回resultN,否则返回default
CASE [test] WHEN[val1] THEN [result]...ELSE [default]END
如果test和valN相等,则返回resultN,否则返回default
IF(test,t,f)
如果test是真,返回t;否则返回f
IFNULL(arg1,arg2)
如果arg1不是空,返回arg1,否则返回arg2
例如:
SELECT IFNULL('bbb','abc'); 结果为: bbb
SELECT IFNULL(null,'abc'); 结果为: abc
NULLIF(arg1,arg2)
如果arg1=arg2返回NULL;否则返回arg1
例如:
SELECT NULLIF('bbb','bbb');结果为: null
SELECT NULLIF('aaa','bbb');结果为: aaa

# 语法
delimiter//
create function 函数名([参数名 参数类型]) # 定义函数
returns 返回值类型 # 设置返回值类型
begin
# 函数逻辑
end//
delimiter;
delimiter//
create function func(i1 int, i2 int)
returns int
begin
declare sum int default 0;
set sum = i1+i2;
return sum;
end//
delimiter;
默默的补一个练习
输入一个数,如果[0,60]返回D,[60,80]返回C,[80,90]返回B,[90,100]返回A
delimiter//
create function func(nub int)
returns char(1)
begin
if nub >= 90 then
return 'A';
elseif nub >= 80 then
return 'B';
elseif nub >=60 then
return 'C';
else
return 'D';
end if;
end//
delimiter;
select func(5,3);
或
写在查询语句中
select func1(1,3),id from person
# 语法
drop function 函数名;
drop function func;
函数 | 存储过程 |
---|---|
一般用于计算数据 | 完成特定的任务 |
声明为FUNCTION | 声明为PROCEDURE |
需要描述返回值类型,且PL/SQL中至少有一个有效的RETURN语句 | 无返回值类型,可通过OUT/INOUT参数返回多个值 |
不能独立运行,必须作为表达式的一部分 | 可作为一个独立的PL/SQL语句运行 |
在DML和DQL中可调用函数 | 在DML和DQL 中不可调用存储过程 |
DML 数据操作语句
DQL 数据查询语句
一组SQL语句执行,要么全部成功,要么全不成功
ACID 原子性(Atom)、一致性(Consistent)、隔离性(Isolate)、持久性(Durable)
注意: SET AUTOCOMMIT=0 禁止自动提交 和 SET AUTOCOMMIT=1开启自动提交
create table account(
id int(50) not null auto_increment primary key,
name VARCHAR(50) not null,
money DOUBLE(8,2) not NULL
);
insert into account (name,money) values('鲁班',250),('后羿',5000);
start TRANSACTION;
update account set money = money+500 where id=1;
update account set money = money-500 where id=2;
commit;
select * from account;
start transaction;
update account set money = money+500 where id=1;
update account set money = money-500 where id=2;
rollback;
START TRANSACTION ;
insert into account (name,money) values('李元芳',1000);
SAVEPOINT s1; -- 设置保存点
insert into account (name,money) values('张桂枝',1500);
ROLLBACK to s1; -- 事物回滚到保存点<br>COMMIT; --提交事物
create procedure p1(out flag char(1))
begin
declare m int default 0;
start TRANSACTION;
update account set money = money-500 where id=1;
update account set money = money+500 where id=2;
select money into m from account where id=1;
if m > 0 then
commit;
set flag = 'T';
else
rollback;
set flag = 'F';
end if;
end;
set @flag='F';
call p1(@flag);
select @flag;
select * from account;

当并发事务同时访问一个资源时,有可能导致数据不一致,因此需要一种机制来将数据访问顺序化,以保证数据库数据的一致性。
innoDB的行级锁分为两种类型:共享锁(乐观所)和排他锁(悲观锁)
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block(阻塞)直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制.
要使用悲观锁,我们必须关闭mysql数据库的自动提交属性.因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。关闭自动提交命令为:set autocommit=0;
# 加锁
for update
模拟多人同时操作一条数据
-- 0.开始事务
start transaction;
-- 1.查询账户余额
set @m = 0; -- 账户余额
select money into @m from account where id = 1 for update;
select @m;
-- 2.修改账户余额
update account set money = @m -100 where id = 1;
select * FROM account where id = 1;
-- 3. 提交事务
commit;
在另外的查询页面执行:
-- 0.开始事务
start transaction;
-- 1.查询账户余额
set @m = 0; -- 账户余额
select money into @m from account where id = 1 for update;
select @m;
-- 2.修改账户余额
update account set money = @m +100 where id = 1;
select * FROM account where id = 1;
-- 3. 提交事务
commit;
会发现当前查询会进入到等待状态,不会显示出数据,当上面的sql执行完毕提交事物后,当前sql才会显示结果.
注意1:在使用悲观锁时,如果表中没有指定主键,则会进行锁表操作.
注意2: 悲观锁的确保了数据的安全性,在数据被操作的时候锁定数据不被访问,但是这样会带来很大的性能问题。因此悲观锁在实际开发中使用是相对比较少的。
每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现 方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录 的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数 据。
-- 1.查询账户余额
set @m = 0; -- 账户余额
select money into @m from account where id = 1 ;
select @m;
-- 2.查询版本号
set @version = 0; -- 版本号
select version into @version from account where id = 1 ;
select @version;
-- 3.修改账户余额
update account set money = @m -100,version=version+1 where id = 1 and version = @version;
select * FROM account where id = 1;
2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳 (datatime), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
两种锁各有其有点缺点,不能单纯的讲哪个更好.
InnoDB的锁定模式实际上可以分为四种:共享锁(S),排他锁(X),意向共享锁(IS)和意向排他锁(IX)。我们可以通过以下表格来总结上面这四种所的共存逻辑关系:
共享锁(S) | 排他锁(X) | 意向共享锁(IS) | 意向排他锁(IX) |
---|---|---|---|
共享锁(S) | 兼容 | 冲突 | 兼容 |
排他锁(X) | 冲突 | 冲突 | 冲突 |
意向共享锁(IS) | 兼容 | 冲突 | 兼容 |
意向排他锁(IX) | 冲突 | 冲突 | 兼容 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。