Mysql基础篇-查询、函数、多表、事务

1. 基础篇

1.1 mysql用户和权限管理

查询用户

USER mysql;
SELECT * FROM user;

创建用户

CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';

例如:

-- 创建用户cc,只能在当前主机localhost访问,密码1234
create user 'cc'@'localhost' identified by '1234';

--创建用户gg,可以再任意主机访问改数据库,密码
create user 'gg'@'%' identified by '1234';

修改用户密码

ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码'

删除用户

DROP USER '用户名'@'主机名'
  • 权限管理
    查询权限
show grants for '用户名'@'主机名';

授予权限

grant 权限列表 on 数据库名.表名 to '用户名'@'主机名'

例如给cc授予权限

grant all on testDb.table1 to 'cc'@'%';

撤销权限

revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名'

1.2 执行顺序

  • 查询语句执行顺序问题:
    image
    验证:根据执行顺序,以下会报错
select user_name un from ussers where un = 'tom'

首先执行 From 表名列表操作
然后执行 where 条件列表 来指定查询条件
接着执行 Group By和Having 指定分组和分组之后的条件
第四步执行 Select 来决定查询返回哪些子段
后面再分别执行 Order By 和 Limi

  • 聚合函数
    | 函数 | 功能 |
    | ------------ | ------------ |
    | count |统计数量 |
    | max | 最大值 |
    | min | 最小值 |
    | avg | 求平均 |
    | sum | 求和 |
    注意:Null值不参与所有的聚合函数运算

1.3 order_by 问题

列的别名只能在ORDER_BY中使用,不能再WHERE中使用,如下会报错

SELECT SELECT employee_id,salary,salary * 12 annual_sal
FROM employees
WHERE annual_sal > 81600;

1.4 二级排序

  • 可以使用不在select列表中的列排序
  • 在对多列进行排序的时候,首先排序的第一列必须有相同的列值,才会对第二列进行排序,如果第一列数据中所有的值都是唯一的,将不再对第二列进行排序

1.5 笛卡尔积(交叉连接)理解

笛卡尔积是一个数学运算,假设有两个集合X和Y,那么X和Y的笛卡尔积就是X和Y的所有可能组合,也就是第一个对象来自于X,第二个对象来自于Y的所有可能。组合的个数为两个集合中元素个数的乘积数。
image

  • sql92中笛卡尔积成为交叉连接英文为CROSS JOIN。在SQL99中也是使用CROSS JOIN表示交叉连接,它的作用就是把任意表进行连接,即使两张表不相关,以下的情况会出现笛卡尔积现象:
#查询员工姓名和所在部门名称
SELECT last_name,department_name FROM employees,departments;
SELECT last_name,department_name FROM employees CROSS JOIN departments;
SELECT last_name,department_name FROM employees INNER JOIN departments;
SELECT last_name,department_name FROM employees JOIN departments;

笛卡尔积的错误会在下面条件下产生:

  1. 省略多个表的连接条件(或关联条件)
  2. 连接条件(或关联条件)无效
  3. 所有表中的所有行相互连接
    避免,在where加入有效的连接条件SELECT 字段列表 FROM 表1, 表2 WHERE 条件 ...;

1.5.1 内连接查询

内连接查询的是两张表交集部分
隐式内连接:

SELECT 字段列表 FROM 表1, 表2 WHERE 条件 ...;

显式内连接

SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ...;

显示性能比隐式高
例如:

-- 查询员工姓名,及关联的部门的名称
-- 隐式
select e.name, d.name from employee as e, dept as d where e.dept = d.id;
-- 显式
select e.name, d.name from employee as e inner join dept as d on e.dept = d.id;

1.5.2 外连接查询

左外连接:
查询左表所有数据,一级两张表交集部分数据

SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ...;

想当于查询表1的所有数据,包含表1和表2交集部分数据

右外连接
查询右表所有数据,以及两张表交集部分数据

SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ...;

例如:

-- 左
select e.*, d.name from employee as e left outer join dept as d on e.dept = d.id;
select d.name, e.* from dept d left outer join emp e on e.dept = d.id;  -- 这条语句与下面的语句效果一样
-- 右
select d.name, e.* from employee as e right outer join dept as d on e.dept = d.id;

1.5.3自连接查询

SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ...;

自连接查询,可以是内连接查询,也可以是外连接查询
例如:

-- 查询员工及其所属领导的名字
select a.name, b.name from employee a, employee b where a.manager = b.id;
-- 没有领导的也查询出来
select a.name, b.name from employee a left join employee b on a.manager = b.id;

1.5.5 联合查询 union

把多次查询的结果合并,形成新的查询集
语法:

SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...

注意事项:

  • UNION ALL会有重复结果,UNION 不会
  • 联合查询比使用or效率高,不会使索引失效

1.5.6 子查询

嵌套查询也称为子查询
子查询的外部的语句可以是INSERT/UPDATE/DELETE/SELECT中的任何一个
根据子查询结果可以分为

  • 标量子查询 (子查询的结果为单个值)
  • 列子查询(子查询的结果为一列)
  • 行子查询(子查询的结果为一行)
  • 表子查询(子查询的结果为多行多列)
    (1)列子查询
    子查询返回的结果为一列(可以是多行)
    常用的操作符
    | 操作符 |描述 |
    | ------------ | ------------ |
    | IN | 在指定的集合范围内,多选一 |
    | NOT IN | 不在指定的集合范围内 |
    | ANY |子查询返回列表中,有任意一个满足即可 |
    | SOME |与ANY等同,使用some的地方都可以使用any|
    |ALL | 子查询返回列表的所有值都必须满足 |
    例子:
-- 查询销售部和市场部的所有员工信息
select * from employee where dept in (select id from dept where name = '销售部' or name = '市场部');
-- 查询比财务部所有人工资都高的员工信息
select * from employee where salary > all(select salary from employee where dept = (select id from dept where name = '财务部'));
-- 查询比研发部任意一人工资高的员工信息
select * from employee where salary > any (select salary from employee where dept = (select id from dept where name = '研发部'));

(2)行子查询
返回的结果是一行(可以是多列)
常用操作符:= ,<,>,IN, NOT IN,exists
例子:

-- 查询与xxx的薪资及直属领导相同的员工信息
select * from employee where (salary, manager) = (12500, 1);
select * from employee where (salary, manager) = (select salary, manager from employee where name = 'xxx');
select department_name from departments d where EXITS(
	select * from employees e where e.department_id = d.department_id
)

1.6 函数

1.6.1 字符串函数

函数 功能
CONCAT(S1,S2,...,Sn) 字符串拼接,将S1,S2...Sn拼接成一个字符串
LOWER(str) 将字符串str全部转为小写
UPPER(str) 将字符串全部转为大写
LPAD(str,n,pad) 左填充,用字符串pad对str的左边进行填充,达到n
个字符串长度
RPAD(str,n,pad) 右填充,用字符串pad对str的右边进行填充,达到n个字符串长度
TRIM(str) 去掉字符串头部和尾部的空格
SUBSTRING(str,start,len) 返回从字符串str的start位置起的len长度字符串
例如:
-- 切片(起始索引为1)
SELECT SUBSTRING('Hello World', 1, 5);

1.6.2 数值函数

函数 功能
CEIL(x) 向上取整
FLOOR(x) 向下取整
MOD(x,y) 返回x/y的模
RAND() 返回0-1内的随机数
ROUND(x,y) 求参数x的四舍五入值,保留y位小数

1.6.3 日期函数

函数 功能
CURDATE() 返回当前日期
CURTIME() 返回当前时间
NOW() 返回当前日期和时间
YEAR(date) 获取指定date的年份
MONTH(date) 获取指定date的月份
DAY(date) 获取指定date的日期
DATE_ADD(date,INTERVAL expr type) 返回一个日期/时间值加上一个时间间隔expr后的时间值
DATEDIFF(date1,date2) 返回起始时间date1和结束时间date2之间的天数

例如:

--查询所员工的入职天数。并根据入职天数倒叙排序
select name,datediff(curdate(),entryDate) as 'entrydays' from emp order by entrydays desc;

1.6.4 流程函数

函数 功能
IF(value,t,f) 如果value为true,则返回t,否则返回f
IFNULL(value1,value2) 如果vaule1不为空,返回value1,否则返回value2
CASE WHEN[val1] THEN[res1] ... ELSE[default] END 如果val1为true,返回res1,...否则返回default默认值
CASE[expr] WHEN [val1] THEN [res1] ... ELSE[default] END 如果expr的值等于val1,返回res1,...否则返回default默认值
例如:
select
	name,
	(case when age > 30 then '中年' else '青年' end
	) ageLevel
from
emp;

select name,
	(case wokeAddr when '北京' then '一线城市' when '上海' then '一线城市' else '二线城市' end) as '工作地址' from emp;

1.7 事务

隐式事务:没有明显的开启和结束,本身就是一条事务可以自动提交,如insert、update、delete
显式事务:具有明显的开启和结束,例如以下格式

1、开启事务
set autocommit=0;#关闭自动提交
start transaction;#开启事务机制

2、编写一组逻辑sql语句
注意:sql语句支持的是insert、update、delete

【设置回滚点,可选项】
savepoint 回滚点名;

3、结束事务
提交:commit;
回滚:rollback;
回滚到指定的地方: rollback to 回滚点名;

1.7.1并发事务问题:

(1)脏读:一个事务读到另一个事务还没提交的数据
image
事务A执行到第二更新了id为1的数据,事务B此时查询,但是事务A还没有执行完提交。导致脏读
(2)不可重复读
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读
image
事务A第一次查询后,第二步事务B进行了更新数据病提交,事务A继续查询和第一次查询的结果不一致
(3)幻读
一个事务按照条件查询数据时,没有对应的数据航,但是插入数据时,发现这行数据已经存在,好像出现幻影
image
事务A第一次查询没有对应数据,事务B插入一条数据,接着查询A能查到

解决以上问题,隔离级别

image

  • √表示在当前隔离级别下该问题会出现
  • Serializable 性能最低;Read uncommitted 性能最高,数据安全性最差

查看事务隔离级别:

SELECT @@TRANSACTION_ISOLATION;

设置事务隔离级别:

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE };

SESSION是会话级别,表示只针对当前会话有效,GLOBAL表示对所有会话有效

1.7.2 丢失更新(写问题)

一、定义
在事务的隔离级别内容中,能够了解到两个不同的事务在并发的时候可能会发生数据的影响。脏读、不可重复读,幻读三个问题都是事务A对数据进行修改、增加,事务B总是在做读操作。如果两事务都在对数据进行修改则会导致另外的问题,丢失更新。
解决:
(1)悲观锁:认为两个事务更新操作一定会发生丢失更新
解决:通过在语句后面添加 for update来实现行级上锁,所以又称为行级锁。例如:select * from t_account t where id = 'id' for update;
(2)乐观锁:认为事务不一定会产生丢失更新,让事务进行并发修改,不对事务进行锁定
解决:由程序员自己解决,可以通过给数据表添加自增的version或时间戳timestamp,进行数据修改时,数据库会检测version字段或者时间戳是否与原来的一致,若不一致,抛出异常或重新查询

posted @ 2022-07-29 14:40  spiderMan1-1  阅读(31)  评论(0编辑  收藏  举报