×

MySQL

MySQL语法2

小飞侠 小飞侠 发表于2020-11-22 15:22:22 浏览1300 评论0

抢沙发发表评论


1. 视图

1.1 创建视图

--格式:CREATE VIEW 视图名称 AS  SQL语句
CREATE VIEW V1 AS
SELECT cid,cname,teacher_id,tname FROM course
LEFT JOIN teacher ON course.teacher_id=teacher.tid

1.2  删除视图

--格式:DROP VIEW 视图名称
DROP VIEW V1

1.3 修改视图

-- 格式:ALTER VIEW 视图名称 AS SQL语句
ALTER VIEW V1 AS
SELECT cid,cname,tname FROM course
LEFT JOIN teacher ON course.teacher_id=teacher.tid

1.4  使用视图

使用视图时,将其当作表进行操作即可,由于视图是虚拟表,所以无法使用其对真实表进行创建、更新和删除操作,仅能做查询用。

SELECT * FROM V1

2. 触发器

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

2.1 创建语法

-- delimiter // 更改mysql语句默认结束符号(默认为;)
-- NEW 表示update、insert前的临时表
-- OLD 表示delete前的临时表
-- NEW表示即将插入的数据行,OLD表示即将删除的数据行。
-- 插入前
delimiter //  
CREATE TRIGGER TRI_BEFORE_INSERT_a1 BEFORE INSERT ON a FOR EACH ROW
BEGIN
insert into b(num) VALUES (NEW.num);
END //
delimiter ;
-- 插入后
delimiter //
CREATE TRIGGER TRI_AFTER_INSERT_a2 AFTER INSERT ON a FOR EACH ROW
BEGIN
INSERT INTO b(num) VALUES(NEW.num+5);
END //
delimiter ;
-- 删除前
delimiter //
CREATE TRIGGER TRI_BEFORE_DELETE_a3 BEFORE DELETE ON a FOR EACH ROW
BEGIN
delete from b where num = OLD.num;
END //
delimiter ;
-- 删除后
delimiter //
CREATE TRIGGER TRI_AFTER_DELETE_a4 AFTER DELETE ON a FOR EACH ROW
BEGIN
delete from b where num = OLD.num+5;
END //
delimiter ;
-- 更新前
delimiter //
CREATE TRIGGER TRI_BEFORE_UPDATE_a5 BEFORE UPDATE ON a FOR EACH ROW
BEGIN
UPDATE b set num = NEW.num WHERE b.num = OLD.num; -- a表变动b表相同的数字跟着变动
END //
delimiter ;
-- 更新后
delimiter //
CREATE TRIGGER TRI_AFTER_UPDATE_a6 AFTER UPDATE ON a FOR EACH ROW
BEGIN
UPDATE b set num = NEW.num WHERE b.num = OLD.num; -- a表变动b表相同的数字跟着变动
END //
delimiter ;

2.2 删除触发器

DROP TRIGGER 触发器名称;

3.存储过程

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

3.1 创建存储过程

3.1.1  无参数过程
delimiter //
CREATE PROCEDURE P1()
BEGIN
SELECT * FROM SCORE;
END //
delimiter ;
-- 执行存储过程
call P1()
3.1.2 有参数过程

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

  • in 仅用于传入参数作用

  • out 仅用于返回值用

  • inout 既可以传入又可以当作返回值

-- 创建存储过程
delimiter //
CREATE PROCEDURE P2(
in i1 int,
in i2 int,
inout i3 int,
out r1 int
)
BEGIN
DECLARE tmp1 int;
DECLARE tmp2 int default 0;
set tmp1 = 1;
set r1 = i1+i2+tmp1+tmp2;
set i3 = i3+100;
END //
delimiter ;
-- 执行存储过程
set @t1 = 100;
set @t2 = 0;
call p2(3,4,@t1,@t2);
select @t1,@t2;
3.1.2.1 带结果集的存储过程
delimiter //
CREATE PROCEDURE P3()
BEGIN
SELECT * FROM SCORE;
END //
delimiter ;
3.1.2.2 结果集+OUT值
delimiter //
CREATE PROCEDURE P4(
in n1 int,
inout n3 int,
out n2 int
)
BEGIN
DECLARE tmp1 int;
DECLARE tmp2 int default 0;
SELECT * FROM SCORE;
SET n2 = n1 + 100;
SET n3 = n3 + n1 +100;
END //
delimiter ;
3.1.2.3 带事务的存储过程
delimiter //
CREATE PROCEDURE P5(
OUT return_code tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
 -- ERROR
 SET return_code = 1;
 rollback;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
SET return_code = 2;
rollback;
END;
START TRANSACTION;
DELETE FROM b;
insert into a(num) values(99);
COMMIT;
--SUCCESS
SET return_code = 0;
END //
delimiter ;
3.1.2.4 带游标的存储过程
delimiter //
CREATE PROCEDURE P6()
BEGIN
declare ssid int;
declare ssname varchar(50);
declare done int default FALSE;
declare my_cursor CURSOR FOR SELECT sid,sname from student;
declare continue handler for NOT FOUND SET done = TRUE;
open my_cursor;
eg:LOOP
 fetch my_cursor into ssid,ssname;
 if done then
  leave eg;
 end if;
 insert into teacher(tname) values(ssname);
END loop eg;
CLOSE my_cursor;
END //
delimiter ;
3.1.2.5 动态执行SQL
delimiter //
CREATE PROCEDURE P7(
in nid int
)
BEGIN
set @nnid = nid;
-- PREPARE 把...准备好
PREPARE prod FROM 'SELECT * FROM student where sid > ?';
EXECUTE prod USING @nnid;
DEALLOCATE PREPARE prod;
END //
delimiter ;

3.2 删除存储过程

drop procedure proc_name;

3.3 执行存储过程

-- 无参数
CALL Proc_name()
-- 有参数,全in
CALL proc_name(参数1,参数2,...)
-- 有参数,有in,out,inout
set @t1 = 0;
set @t2 = 5;
CALL proc_name(1,2,@t1,@t2)
SELECT @t1,@t2
# pymysql执行存储过程
import pymysql
conn = pymysql.connect(host='localhost', user='root', password='******', database='db1' )
cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
cur.callproc('p7', args=(1,))
ret = cur.fecthall()
print(ret)
cur.close()
conn.close()

3.函数

3.1 内置函数

MySQL中提供了许多内置函数,例如:

 CHAR_LENGTH(str)
       返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
       对于一个包含五个二字节字符集, LENGTH()返回值为 10, 而CHAR_LENGTH()的返回值为5。

   CONCAT(str1,str2,...)
       字符串拼接
       如有任何一个参数为NULL ,则返回值为 NULL。
   CONCAT_WS(separator,str1,str2,...)
       字符串拼接(自定义连接符)
       CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。

   CONV(N,from_base,to_base)
       进制转换
       例如:
           SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示

   FORMAT(X,D)
       将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若  D 为 0, 则返回结果不带有小数点,或不含小数部分。
       例如:
           SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
   INSERT(str,pos,len,newstr)
       在str的指定位置插入字符串
           pos:要替换位置其实位置
           len:替换的长度
           newstr:新字符串
       特别的:
           如果pos超过原字符串长度,则返回原字符串
           如果len超过原字符串长度,则由新字符串完全替换
   INSTR(str,substr)
       返回字符串 str 中子字符串的第一个出现位置。

   LEFT(str,len)
       返回字符串str 从开始的len位置的子序列字符。

   LOWER(str)
       变小写

   UPPER(str)
       变大写

   LTRIM(str)
       返回字符串 str ,其引导空格字符被删除。
   RTRIM(str)
       返回字符串 str ,结尾空格字符被删去。
   SUBSTRING(str,pos,len)
       获取字符串子序列

   LOCATE(substr,str,pos)
       获取子序列索引位置

   REPEAT(str,count)
       返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
       若 count <= 0,则返回一个空字符串。
       若str 或 count 为 NULL,则返回 NULL 。
   REPLACE(str,from_str,to_str)
       返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
   REVERSE(str)
       返回字符串 str ,顺序和字符顺序相反。
   RIGHT(str,len)
       从字符串str 开始,返回从后边开始len个字符组成的子序列

   SPACE(N)
       返回一个由N空格组成的字符串。

   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);
           -> 'ratically'

       mysql> SELECT SUBSTRING('foobarbar' FROM 4);
           -> 'barbar'

       mysql> SELECT SUBSTRING('Quadratically',5,6);
           -> 'ratica'

       mysql> SELECT SUBSTRING('Sakila', -3);
           -> 'ila'

       mysql> SELECT SUBSTRING('Sakila', -5, 3);
           -> 'aki'

       mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
           -> 'ki'

   TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
       返回字符串 str , 其中所有remstr 前缀和/或后缀都已被删除。若分类符BOTH、LEADIN或TRAILING中没有一个是给定的,则假设为BOTH 。 remstr 为可选项,在未指定情况下,可删除空格。

       mysql> SELECT TRIM('  bar   ');
               -> 'bar'

       mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
               -> 'barxxx'

       mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
               -> 'bar'

       mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
               -> 'barx'

更多函数 ----> 中文点击这里  官方点击这里

3.2 自定义函数

delimiter // CREATE FUNCTION F1( i1 int, i2 int ) returns int BEGIN DECLARE num int; set num = i1 + i2; return(num); END // delimiter ;

3.3 删除函数

drop function func_name;

3.4 执行函数

-- 获取返回值
DECLARE @i varchar(32);
SELECT UPPER('alex') into @i;
SELECT @i;
-- 在查询中使用
SELECT F1(100,200),name FROM tb2;

4 .事务

4.1 支持事务的存储过程

delimiter //
CREATE PROCEDURE P5(
OUT return_code tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
 -- ERROR
 SET return_code = 1;
 rollback;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
SET return_code = 2;
rollback;
END;
START TRANSACTION;
DELETE FROM b;
insert into a(num) values(99);
COMMIT;
--SUCCESS
SET return_code = 0;
END //
delimiter ;

-- 执行存储过程
DECLARE @n int;
set @n = 5;
call p5(@n);
select @n;

5 .索引

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

  • 普通索引 仅加速查询

  • 唯一索引 加速查询+列值唯一(可以有Null)

  • 主键索引 加速查询+列值唯一+表中只有一个(不可以有null)

  • 组合索引 多列值组成一个索引,专门用于组合搜索,其效率大于索引合并

  • 全文索引 对文本的内容进行分词,进行搜索 PS:索引合并:使用多个单列索引组合搜索 PS:覆盖索引:select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖

5.1 普通索引

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

5.1.1 创建表时建立普通索引
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)
)
5.1.2 创建普通索引
create index 索引名称 on 表名(列名)
-- 注意:对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。
create index ix_extra on in1(extra(32));
5.1.3 删除普通索引
drop index 索引名称 on 表名
5.1.4 查看索引
show index from 表名

5.2 唯一索引

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

5.2.1 创建表时建立唯一索引
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)
)
5.2.2 创建唯一索引
create unique index 索引名称 on 表名(列名)
5.2.3 删除唯一索引
drop unique index 索引名称 on 表名

5.3 主键索引

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

5.3.1 创建表时建立主键索引
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 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)
)
5.3.2 创建主键
alter table 表名 add primary key(列名)
5.3.3 删除唯一索引
alter table 表名 drop primary key;
alter table 表名 modify 列名 int,drop primary key;

5.4 组合索引

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

5.4.1 创建表
create table in3(
   nid int not null auto_increment primary key,
   name varchar(32) not null,
   email varchar(64) not null,
   extra text
)
5.4.2 创建组合索引
create index 索引名称 on 表名(name,email,...)
-- 如上创建组合索引之后,查询:
-- name and email  -- 使用索引
-- name                 -- 使用索引
-- email                 -- 不使用索引
-- 注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并。

5.5 索引补充

5.5.1 相关命令(查看表结构、生成表的SQL、查看索引、执行时间)
-- 查看表结构
desc 表名
-- 查看生成表的SQL
show create table 表名
-- 查看索引
show index from 表名
-- 查看执行时间
SET profiling =1;
SQL...
SHOW profiles;
5.5.2 使用索引和不使用索引

由于索引是专门用于加速搜索而生,所以加上索引之后,查询效率会快到飞起来。

-- 有索引
mysql> select * from tb1 where name = 'wupeiqi-888';
+-----+-------------+---------------------+----------------------------------+---------------------+
| nid | name        | email               | radom                            | ctime               |
+-----+-------------+---------------------+----------------------------------+---------------------+
| 889 | wupeiqi-888 | wupeiqi888@live.com | 5312269e76a16a90b8a8301d5314204b | 2016-08-03 09:33:35 |
+-----+-------------+---------------------+----------------------------------+---------------------+
1 row in set (0.00 sec)

-- 无索引
mysql> select * from tb1 where email = 'wupeiqi888@live.com';
+-----+-------------+---------------------+----------------------------------+---------------------+
| nid | name        | email               | radom                            | ctime               |
+-----+-------------+---------------------+----------------------------------+---------------------+
| 889 | wupeiqi-888 | wupeiqi888@live.com | 5312269e76a16a90b8a8301d5314204b | 2016-08-03 09:33:35 |
+-----+-------------+---------------------+----------------------------------+---------------------+
1 row in set (1.23 sec)
5.5.3 正确使用索引

数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。 即使建立索引,索引也不会生效:

- like '%xx'
   select * from tb1 where name like '%cn';
- 使用函数
   select * from tb1 where reverse(name) = 'wupeiqi';
- or
   select * from tb1 where nid = 1 or email = 'seven@live.com';
   特别的:当or条件中有未建立索引的列才失效,以下会走索引
           select * from tb1 where nid = 1 or name = 'seven';
           select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
- 类型不一致
   如果列是字符串类型,传入条件是必须用引号引起来,不然...
   select * from tb1 where name = 999;
- !=
   select * from tb1 where name != 'alex'
   特别的:如果是主键,则还是会走索引
       select * from tb1 where nid != 123
- >
   select * from tb1 where name > 'alex'
   特别的:如果是主键或索引是整数类型,则还是会走索引
       select * from tb1 where nid > 123
       select * from tb1 where num > 123
- order by
   select email from tb1 order by name desc;
   当根据索引排序时候,选择的映射如果不是索引,则不走索引
   特别的:如果对主键排序,则还是走索引:
       select * from tb1 order by nid desc;

- 组合索引最左前缀
   如果组合索引为:(name,email)
   name and email       -- 使用索引
   name                 -- 使用索引
   email                -- 不使用索引
5.5.4 其他注意事项
- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 创建表时尽量时 char 代替 varchar
- 表的字段顺序固定长度的字段优先
- 组合索引代替多个单列索引(经常使用多个条件查询时)
- 尽量使用短索引
- 使用连接(JOIN)来代替子查询(Sub-Queries)
- 连表时注意条件类型需一致
- 索引散列值(重复少)不适合建索引,例:性别不适合

6 .条件语句、循环语句、动态SQL

6.1 条件语句

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 ;

6.2 循环语句

6.2.1 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 ;
6.2.2 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 ;
6.2.3 loop循环
begin
declare i int default 0;
loop_label:loop
 set i=i+1;
 if i<8 then
  iterate loop_label;
 end if;
 select i;
end loop loop_label;
end
6.3 动态执行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 c where id > ?';
execute prod using @p1;
deallocate prepare prod;
end //
delimiter ;


欢迎评论

访客