MySQL数据库:用户管理、基本数据类型、对数据库、表、表内容的操作、完整性约束条件、pymysql模块、视图、存储过程、触发器

1. MySQL用户和权限管理

1)创建账号

create user "用户名"@"IP地址" identified by "密码";
创建本地账号
create user 'adam1'@'localhost' identified by '123'; #mysql -adam1 -p123
创建远程账号
create user 'adam2'@'192.168.31.10' identified by '123'; #mysql -uadam2 -p123 -h 服务端ip
create user 'adam3'@'192.168.31.%' identified by '123'; #mysql -uadam3 -p123 -h 服务端ip


2)授权

user: *.*

db: db1.*

tables_priv: db1.t1

columns_priv: id, name


授予权限
grant all on *.* to 'adam1'@'localhost';
grant select on *.* to 'adam1'@'localhost';
grant select on db1.* from 'adam1'@'localhost';

回收权限
revoke select on *.* from 'adam1'@'localhost';
revoke select on db1.* from 'adam1'@'localhost';

查看权限:
show grants for 'adam1'@'localhost';


3)删除用户

drop user "用户名"@"IP地址";


4)修改用户

rename user "用户名"@"IP地址"; to "新用户名"@"IP地址";


5)修改密码

set password for "用户名"@"IP地址" = Password("新密码");


常用权限:

all privileges 除grant外的所有权限

select 仅查询权限

select, insert 查询和插入权限

update 使用update

delete 使用delete



2. MySQL基础知识

1)主键:一种特殊的唯一索引,不允许有空值,如果主键使用单格列,则它的值必须唯一,如果是多列,则其组合必须唯一。

primary key [auto_increment]

后一个参数为自增

2)对数据库的基本操作

create database db1 charset utf8:创建数据库

show databases:查看数据库

alter database db1 charset gbk:修改数据库

drop database db1:删除数据库




3.  MySQL基本数据类型

1)数字

tinyint:小整数

smallint: 

mediumint:

int:整数

bigint:大整数

decimal:准确的小数值,对于精确数值计算时需要用此类型

float:单精度浮点数,数值越大越不准确

double:双精度浮点数,数值越大越不准确



2)字符串

char:定长

varchar:变长

text:用于保存变长的大字符串

medium:

longtext:


3)时间

date:YYYY-MM-DD

time:HH:MM:SS

year:YYYY

datetime:YYYY-MM-DD HH:MM:SS

timestamp:YYYY-MM-DD HH:MM:SS


4)枚举类型与集合类型

enum 单选,只能在给定的范围内选一个值,例:gender enum('Male', 'Female')

set 多选,在给定的范围内可以选择一个或多个值,例:hobby set('Music', 'Sports', 'Reading')



4. 对数据库的操作

1)创建数据库

CREATE DATABASE 数据库名 charset utf8; 

2)数据库命名规则:

  • 可以由字母、数字、下划线、@、#、¥
  • 区分大小写
  • 唯一性
  • 不能使用关键字如create select
  • 不能单独使用数字
  • 最长128位

3)数据库相关操作

(1)查看数据库

show databases;

show create database db1;

select database();

(2)选择数据库

USE 数据库名

(3)删除数据库

DROP DATABASE 数据库名;

(4)修改数据库

alter database db1 charset utf8;



5. 对表操作的内容

1)创建表

create table 表名(列名 类型 约束条件)

注意:

1. 在同一张表中,字段名是不能相同

2. 宽度和约束条件可选

3. 字段名和类型是必须的

2)删除表

drop table 表名

3)清空表

truncate table 表名

delete from 表名

4)修改表

添加列:

    alter table 表名 add 列名 类型 [完整性约束条件]

    alter table 表名 add 列名 类型 [完整性约束条件] FIRST

    alter table 表名 add 列名 类型 [完整性约束条件] AFTER 列名

删除列:alter table 表名 drop column 列名

修改列:

    alter table 表名 modify column 列名 类型 [完整性约束条件];

    alter table 表名 change 原列名 新列名 类型 [完整性约束条件];

添加主键:

    alter table 表名 add primary key(列名);

删除主键:

    alter table 表名 drop primary key(列名);

5)复制表

(1)复制表结构+记录(key不会复制:主键、外键和索引)

create table new_service select * from service;

(2)只复制表结构

create table new_service1 select * from service where 1 = 2;

create table new_service2 like service;

6. 表内容操作

1)增

insert into table(col, col...) values (val, val...), (val, val...);

insert into table(col, col...) select (col, col...) from table

2)删

delete from table

delete from table where id=1 and name="Steve"

3)改

update table set name="Bill" where id=2

4)查

select * from table

select * from table where id=1

select id,name as aaa from table where id>1

select concat('姓名: ', name, ' 性别: ', sex) from employee;

5)其他

a where约束条件,可以使用以下条件

  • 比较运算符:> < >= <= <> !=
  • between 80 and 100 值在80到100之间
  • in(80, 90, 100) 值是10或20或30
  • 模糊匹配:like 'bo%', pattern可以使%或_,%表示任意多字符,_表示一个字符
  • 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not

select * from table where id in (11,22,33)

b 限制

select * from table limit 5 offset 4 从第4行开始的5行(分页操作可以使用这个查询语句)

c 排序

select * from table order by col desc 根据列从大到小排列

d 分组,group by

分组之后只能取分组的字段,以及每个组聚合的结果

设置只能取分组的字段:set global sql_mode = "ONLY_FULL_GROUP_BY"

select num from table group by num

select post, group_concat(name) from employee group by post

注:group by 必须在where之后,order by之前

select count(id) from table group by department having count(id) > 5;

e 正则表达式

select * from employee where name regexp '^ab';

等价于:select * from employee where name like 'ab%';

单表查询小结:

语法顺序
select distinct 字段1, 字段2, 字段3 from 库.表
  where 条件
  group by 分组条件
  having 过滤
  order by 排序字段
  limit n; 限制显示个数


f 连表操作

select A.id, A.name, B.name from A, B

where A.id = B.id


内连接:

select * from emp
inner join dep
on emp.dep_id = dep.id

左连接:在内连接的基础上保留左表的记录
select * from emp
left join dep
on emp.dep_id = dep.id
右连接:在内连接的基础上保留右表的记录
select * from emp
right join dep
on emp.dep_id = dep.id

全外连接:在内连接的基础上保留左右两表没有对应关系的记录

select * from emp
left join dep
on emp.dep_id = dep.id
union
select * from emp
right join dep
on emp.dep_id = dep.id


不处理重合:

select name from A

union all

select name from B


6)select语句关键字的定义顺序

SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

7)子查询

子查询是将一个查询语句嵌套在另一个查询语句中

内层查询语句的查询结果,可以为外层查询语句提供查询条件

子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS和NOT EXISTS等关键字

还可以包含比较运算符: >, <, >=, <=等

查询平均年龄在25岁以上的部门名
select name from department where id in
(select dept_id from employee 
group by dept_id
having avg(age) > 25);
查看技术部员工姓名
select name from employee where dept_id = (select id from department where name='技术');
查看不足1人的部门名
select name from department where id not in
(select distinct dep_id from employee);
查询大于所有人平均年龄的员工名与年龄
select name, age from employee
where age > (
select avg(age) from employee);
带EXISTS关键字的子查询
select * from employee
where EXISTS
(select id from department where name='IT');
每个部门最新入职的那名员工
select * from employee as t1
inner join
(select post, max(hire_date) as max_hire_date from employee
group by post) as t2
on t1.post = t2.post where t1.hire_date = t2.max_hire_date







7. 完整性约束条件

1)not null:非空,not null default 'Default Value',非空且指定默认值

2)unique:限制字段传入的值必须唯一,不能重复

单列唯一:
create table dept(
  id int unique,
  name char(50) unique);

联合唯一:
create table service(
  id init,
  ip char(15),
  port int.
  unique(ip, port));

3)primary key:对于innodb存储引擎来说,一张表内必须有一个主键

4)auto_increment:自增长,该字段必须被定义为key

# 了解
show variables like 'auto_inc%';

# 步长
auto_increment_increment 默认为1
# 起始偏移量
auto_increment_offset 默认1

# 设置步长
set session auto_increment_increment = 5;
set global auto_increment_increment = 5;

# 设置起始偏移量
seg global auto_increment_offset = 1

注意:起始偏移量要<=步长
5)foreign key:外键,
# 先建被关联的表,并且保证被关联的字段唯一
create table dep(
  id int primary key,
  name char(16),
  comment char(50));

# 再建关联的表
create table emp(
  id int primary key,
  name char(10),
  gender emun('Male', 'Female'),
  dep_id int, 
  foreign key(dep_id) references dep(id) on delete cascade on update cascade);

注意:

插入数据时,先往被关联的表中插入数据,再往关联表中插入

删除数据时,先删关联表中的数据,再删被关联的表中的数据

解决这些问题的方法为在建立外键时,添加on delete cascade和on update cascade


6)表之间的关系

1)多对一:多条记录对应一条记录

2)多对多:双向的多对一

3)一对一:一一对应



8. pymysql模块

# -*- coding:utf-8 -*-
import pymysql

# 创建连接
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="root", db="test")

# 创建游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 油表设置为字典类型

# 执行SQL,并返回受影响的行数
# effect_row = cursor.execute("insert into test(id,name) values(%s,%s)", (1,"Steve"))

# 执行SQL,并返回受影响的行数
effect_row = cursor.execute("select * from test where id<5")

# fetchone获取的单条数据
# result = cursor.fetchone()
# cursor.scroll(4, mode="absolute") # 设定绝对位置
# cursor.scroll(-2, mode="relative") # 设定相对位置

data = cursor.fetchall()
print data


# 提交
conn.commit()

# 关闭游标
cursor.close()

# 关闭连接
conn.close()



9. 视图:虚拟表(非真实存在)

1)创建视图

create view v1 

as

select id,name from person

2)删除视图

drop view v1;

3)修改视图

alter view v1 as select * from emp where emp_id > 5;



10. 存储过程

1)创建存储过程

create procedure proc_p1()

begin

    select * from person;

end


2)调用存储过程

call pro_p1;


3)删除存储过程

drop procedure proc_p1;


4)加入变量

create procedure proc_p1(

    in i1 int,  --传入的参数,

    inout ii int, --既是传入也是返回的参数

    out i2 int --返回的参数

 )

begin

    declare d1 int; --声明局部变量

    declare d2 int default 3; 

    

    if i1 = 1 then

        set i2 = 100 + d2;

        set ii = ii + 1;

    elseif i1 = 2 then

        set i2 = 200 + d2;

    else

        set i2 = 1000 + d2;

    end if;


    set d1 = i1 + d2;

    select * from person where id>d2;

end


set @a = 5;

call proc_p1(1, @a, @u); --@u代表在外部定义一个变量

select @a, @u; --查看外部变量



注:将结束符重新设定

delimiter ||


5)在pymysql中执行存储过程

row = cursor.callproc("proc_p1", (1, 2))

# 存储过程的查询结果

cursor.fectchall()

# 获取存储过程的返回值

effect_row = cursor.execute("select @_proc_p1_0, @_proc_p1_1") # @_proc_p1_0表示获取存储过程的第一个值,


6)在语句中对变量进行赋值并在下一条中运用

delimiter $$

drop procedure if exists proc_p2 $$

create procedure proc_p2()

begin

    declare v1 int default 0;

    select departmentId into v1 from person where id = 1;

    select departmentName from department where departmentId=v1;

end $$

delimiter ;



11. 触发器

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


插入前:

CREATE TRIGGER tri_before_insert_tbl BEFORE INSERT ON tb1 FOR EACH ROW

BEGIN

    ```

END


插入后:

CREATE TRIGGER tri_after_insert_tbl AFTER INSERT ON tb1 FOR EACH ROW

BEGIN

    ```

END


删除前:

CREATE TRIGGER tri_before_delete_tbl BEFORE DELETE ON tb1 FOR EACH ROW

BEGIN

    ```

END


删除后:

CREATE TRIGGER tri_after_delete_tbl AFTER DELETE ON tb1 FOR EACH ROW

BEGIN

    ```

END


更新前:

CREATE TRIGGER tri_before_update_tbl BEFORE UPDATE ON tb1 FOR EACH ROW

BEGIN

    ```

END


更新后:

CREATE TRIGGER tri_after_update_tbl AFTER UPDATE ON tb1 FOR EACH ROW

BEGIN

    ```

END


1)案例

delimiter $$

drop trigger if EXISTS tri_before_insert_color $$

CREATE TRIGGER tri_before_insert_color BEFORE INSERT ON color FOR EACH ROW

BEGIN

    if NEW.title = 'red' then

        insert into num(name) values(NEW.title);

    end if;

END $$

delimiter ;


delimiter $$

drop trigger if EXISTS tri_before_delete_color $$

CREATE TRIGGER tri_before_delete_color BEFORE DELETE ON color FOR EACH ROW

BEGIN

    if OLD.title = 'red' then

        insert into num(name) values(OLD.title);

    end if;

END $$

delimiter ;


注意:NEW表示即将插入的数据行,OLD表示即将删除的数据行



11. MySQL函数

CHAR_LENGTH(str) 返回值为字符串str的长度

CONCAT(str1, str2,...) 字符串拼接

CONCAT_WS(separator, str1, str2,...) 字符串拼接(自定义连接符)

FORMAT(X, D) 将数字X的格式写为'#,###,###.##'以四舍五入的方式保留小数点后D位

INSERT(str, pos, len, newstr) 在str的指定位置插入字符串,pos要替换位置的起始位置,len替换的长度,newstr新字符串

INSRT(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

REPLACE(str, from_str, to_str) 返回字符串str以及所有被字符串to_str替代的字符串from_str

REVERSE(str) 返回字符串str,顺序和字符顺序相反

RIGHT(str, len) 返回字符串str,顺序和字符顺序相反

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


1)自定义函数

delimiter  $$

create function f1(

    v1 int,

    v2 int

 )

return int

BEGIN

    declare num int;

    set num = v1 + v2;

    return (num);

END $$

delimiter ;



12. MySQL事务操作

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

delimiter $$

create PROCEDURE p1(

    OUT p_return_code tinyint

 )

BEGIN

    DECLARE exit handler for sqlexception

    BEGIN

        set p_return_code = 1;

        rollback;

    END;


    DECLARE exit handler for sqlwarning

    BEGIN

        set p_return_code = 2;

        rollback;

    END;


    START TRANSACTION;

        DELETE from tb1;

        INSERT into tb2(name) values("Steve");

    COMMIT;


    SET p_return_code = 0;

    END $$

delimiter ;


MySQL动态执行

delimiter $$

DROP PROCEDURE IF EXISTS proc_sql $$

create PROCEDURE proc_sql(

    in strSQL VARCHAR(128),

    in id int

 )

BEGIN

    set @p1 = id;

    set @sql = strSQL;


    PREPARE prod FROM @sql; --编译sql语句,必须传带@符号的变量(全局变量)

    EXECUTE prod USING @p1; --执行,p1代表第一个占位符

    DEALLOCATE prepare prod;

END $$

delimiter ;


call proc_sql('select * from tb1 where id > ?', 5)



13. 事务

start transaction;
update user set balance-=900 where name='a';
update user set balance+=50 where name='b';
update user set balance+=50 where name='c';
commit;




14. 索引

字典的目录,便于数据查找

1)普通索引:只能帮助查找,加速查询

create table tb1(

    id int not null auto_increment primary key,

    name varchar(32) not null,

    email varchar(64) not null,

    extra text,

    index ix_name(name)

 ) engine=innodb default charset=utf8;


create index index_name on table_name(column_name)

drop index_name on table_name;

show index from table_name;


2)唯一索引:只能帮助查找,内容不允许重复,可以为null

create table tb1(

    id int not null auto_increment primary key,

    name varchar(32) not null,

    email varchar(64) not null,

    extra text,

    unique(name)

 ) engine=innodb default charset=utf8;


3)主键索引:只能帮助查找,内容不允许重复,不允许为null,一张表只能有一个主键

4)组合索引:多列共同组成索引,普通多列索引,联合唯一索引,专门用于组合搜索,其效率大于索引合并。如果是左边一个的话或者组合,走索引

5)全文索引:对文本的内容进行分词,进行搜索


6)如何正确使用索引

以下情况不会走索引:

(1)like "%xx": select * from tb1 where name like "%cn";

(2)使用函数:select * from tb1 where reverse(name) = "Steve";

(3)or:select * from tb1 where id = 1 or email = "[email protected]";

当or条件中有未建立索引的列才失效,

(4)类型不一致:如果列是字符串类型,传入条件是必须用引号引起来,不然

(5)!=:select * from tb1 where name != "Steve";

如果是主键,则还是会走索引

(6)>:select * from tb1 where id > 5;

如果是主键或索引是整数类型,则还是会走索引

(7)order by:select email from tb1 order by name desc;

当根据索引排序时,选择的映射如果不是索引,则不走索引

注意:如果对主键排序,则还是走索引:select * from tb1 order by  id desc;



14. 注意事项

1)避免使用select *

2)count(1)或count(col)代替count(*)

3)创建表时尽量用char代替varchar

4)表的字段顺序固定长度的字段优先

5)组合索引代替多个单列索引(经常使用多个条件查询时)

6)尽量使用短索引

7)使用连接(join)来代替子查询

8)连表时注意条件类型需一致

9)索引散列值(重复少)不适合建索引,例:性别不适合



15. MySQL分页

select * from tb1 limit 20000, 5;

第一种优化方法:

select * from tb1 where id > (select id from tb1 limit 20000, 1) limit 5;

第二种方法:

每页10条数据

a. 上一页,下一页

select * from tb1 where id<9999 order by id desc limit 10; --上一页

select * from tb1 where id>1000 order by id desc limit 10; --下一页

b. 上一页,5,6,7,8,9,下一页

从第9页,转到第5页,中间差为40条数据

select * from tb1 where id< (select id from(select id from tb1 where id < 90 order by id desc limit 30) as A order by id asc limit 1) order by id desc limit 10; 



16. 执行计划

explain + 查询SQL - 用户显示SQL执行信息参数,根据参考信息进行SQL优化

最关键的两列:

(1)type:ALL为全表扫描,INDEX全索引扫描,RANGE对索引列进行范围查找,INDEX_MERGE合并索引,REF根据索引找一个或多个值,EQ_REF连接时使用primary key或unique类型,CONST常量(表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次)

(2)rows:mysql估计为了找到所需的行而要读取的行数--之时预估值

其他列:

(1)select_type:SIMPLE简单查询,PRIMARY最外层查询,SUBQUERY映射为子查询,DERIVED子查询,UNION联合,UNION RESULT使用联合的结果




17. 慢日志查询

a, 配置MySQL自动记录慢日志

slow_query_log = OFF 是否开启慢日志记录

long_query_time = 2 时间限制,超过此时间,则记录

slow_query_log_file = /usr/slow.log 日志文件

log_queries_not_using_indexes = OFF 未使用索引的搜索是否记录

注:

查看当前配置信息:show variables like "%query%"

修改当前配置:set global 变量名=值



猜你喜欢

转载自blog.csdn.net/wayne12081213/article/details/79347289