当前位置: 首页 > news >正文

基础语法(二)

Mysql基础语法(二)

Mysql基础语法(二)主要介绍Mysql中稍微进阶一点的内容,会稍微有一些难度(博主个人认为)。学习完基础语法(一)和基础语法(二)之后,建议去尝试50道经典SQL语法题,增强学习和巩固。如下:

  • 在基础语法(一)中,主要是介绍Mysql的基本语法,DDL、DQL、DML语句,以及一些聚合函数,以及数据结构及其函数。
  • 在基础语法(二)中,主要介绍约束、字符串函数,时间函数,逻辑函数,内外连接、子查询。

一、约束

1.1 基本语法

在使用create语句创建数据库表的时候,可以对每一个字段进行约束限制,Mysql中提供了众多的约束,可以根据字段的需求进行限制。如下:

  • NOT NULL:非空约束,见名知意,也就是限制这个字段的值不能是null空值

  • UNIQUE:唯一约束,也是比较好理解,该约束下的字段值只能在整张表出现一次

  • PRIMARY KEY:主键约束,数据库表中每一行数据的唯一标识,该约束下的字段不能为空,且值唯一,也就是说加了主键约束之后,**他的效果相当关于该字段加了非空和唯一约束。**Mysql中一张表只能有一个主键,而且主键的值一般有以下几种方式:
    在这里插入图片描述

  • DEFAULT:默认约束,也就是说你在插入该字段值的时候,如果插入语句没有设定值,Mysql会默认给其一个初值。

  • CHECK:检查约束,插入数据时,会对该字段的插入值进行检查,是否符合约束条件,符合插入,否则失败。

  • FOREIGN KEY:外键约束,用于两张表的连接,保证数据的完整性。(外键在这里有点难说清楚,后面会有实际例子结合,大家更好理解)。
    在这里插入图片描述

添加约束的语法SQL:

-- 定义时添加约束
CREATE TABLE table_name (column_name column_type 约束类型,字段名 字段类型 字段的约束类型,
) ;-- 以下是一个示例,有具体的字段约束
CREATE TABLE test (id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键id,每一条数据的唯一标识,使用主键',name VARCHAR(10) NOT NULL COMMENT '姓名,不能空',phone CHAR(15) UNIQUE NOT NULL COMMENT '电话,这个字段加了两个约束,非空和唯一',age INT CHECK (age BETWEEN 0 AND 120) NOT NULL COMMENT '年龄',status CHAR(1) DEFAULT '1' NOT NULL COMMENT '用户状态,非空,默认值1'
) COMMENT '测试表';

1.2 外键约束

上面讲到的六种约束里面,其实除了外键的其他五种约束,还是挺好理解的,这里稍微讲解一下外键约束。

  • 外键约束其实就是用于保证两张表数据的一致性完整性。可以看下面的例子,根据三大范式,我们可以知道,有一种情况,假如有一个员工表,需要有员工的个人信息和员工所在的部门信息,如果都把这些字段放在一张表的话,造成数据冗余,且不好维护,假如我需要更改一个部门的名字,那么按照这样的做法,我需要将整个表的数据都更新,那么是不是维护成本很大?所以根据三大范式,我们需要拆分两张表,一个表记录员工信息,一个表记录部门的信息,如下,然后使用员工表的里面的一个字段去连接部门表的id,实现信息衔接。
    在这里插入图片描述

  • 这样是不是就解决了上面提到的问题,假如我需要更改部门的名字,是不是只需要更改部门表的一个字段就行,员工表不需要更改。此时,员工表里面的部门表id字段,就是外键了,**连接外表主键(部门表的主键id)**的字段。

  • 那么也许大家会有疑问,我员工表连接着部门表,假如我连接部门表id为1的数据,假如这条数据被删除了,不就造成了数据损失吗。实际上,拥有外键的话,默认情况下,删除数据需要先清楚外键所连接的那一行数据,才能删除,否则删除失败。也就是说,我需要删除部门表id为1的那一行数据,那我需要先去把员工表外键字段里面所有值为1的数据都删除,才能删除部门表id为1的这一行数据,这就是外键之所以能保证数据的完整性和一致性。外键的语法和种类如下**(这个可以看看其他博客,这里不扩展,大家知道有这个东西即可)**:
    在这里插入图片描述

二、内置函数

Mysql中提供了很多内置的函数,主要是字符串处理函数,数值处理函数和时间类函数,分别有各自的场景。

2.1 字符串类

在这里插入图片描述

-- 示例
concat(a,b...n)  -- 拼接,将所有字符串拼接,返回一个总的字符串lower(a)	 -- 全部小写upper(a)	 -- 全部大写lpad(a,n,b) -- 在字符串a左边依次加上b,直到字符串长度达到n值rpad(a,n,b) -- 在字符串a右边依次加上b,直到字符串长度达到n值trim(a) 	-- 去掉字符串a头部和尾部的空格,中间的不去掉substring(s,a,n) 	-- 分割字符串,将字符串s从a开始截取n个长度
  • 应用场景有很多,我这里就简单举例,例如我需要将员工表里的员工id由1改成00001,10改成00010,操作如下:
update table_name set id = lpad(id, 5, '0'); -- 使用lpad函数,对id字段的值进行添加,从左边开始添加,达到5个字符长度

2.2 数值类

在这里插入图片描述

ceil(a) 	-- 向上取整,1.1等于2floor(b) 	-- 向下取整,1.1等于1rand() 		-- 随机获得0-1的一个小数round(a,n) 	-- 对a进行四舍五入,保留n位小数mod(a,b) 	-- 取余
  • 举一个用例,假如用户表的字段是用户的邀请码6位随机数字,那么我需要在插入用户数据是,随机生成一个邀请码插入,如下:
insert into table_name(id,number) values (round(rand()*1000000 , 0);-- 解释:这里id字段可以忽略,我插入值是1,这个不是重点,
-- 重点是后面随机生成6位邀请码的函数,解读一下,首先是使用rand函数随机生成一个小数,然后乘以1000000,然后用round保留0位小数,如0.123456789,乘于10的六次方123456.789,使用round保留0位小数,那就是123457,因为round会四舍五入,不过这里主要是想说明round保留0位小数,达到去除小数的效果-- 也许有细心的小伙伴会发现上面这个例子,有一点问题,例如生成的小数是0.012345... 
-- 那么乘以10的六次方就是12345,不符合,那需要怎么做呢,如下insert into table_name(id,number) values (lpad(round(rand()*1000000 , 0),6,'0'));
-- 解读一下,老做法,生成小数然后乘以10的六次方,假如是上面12345的情况,就用lpad函数补充到六位数,这个只是我的一个做法,不是唯一做法

2.3 日期函数

在这里插入图片描述

curdate() 	-- 目前时间的日期curtime() 	-- 目前时间的timenow() 		-- 现在的时间year(time) 	-- time的年份month(time) -- time的月份day(time) 	-- time的日份date_add(time,num) 	-- time日期加上num后,返回日期datediff(time1,time2) 	-- 计算两个日期相差多少day,time1 - time2
  • 这个的应用场景就更多了,例如我记录插入这条数据的时间,直接在字段值使用now()函数,这里就不举例了,小伙伴们可以发挥想象。

2.4 流程函数

流程函数就是一个SQL里面的逻辑函数,对字段的值进行判断,如果符合xx条件则展示什么,个人觉得这个更多的是前端对值的显示逻辑控制,但是数据库中操作也不少,这里也是介绍一下。

在这里插入图片描述

在这里插入图片描述

  • 上面是一个关于对math、english和chinese三门成绩进行数值判断,多少分则select返回什么等级

三、连接查询

这个是一个重点知识,实际的生产环境中,都会用到这个,一定要仔细学。

3.1 场景介绍

连接查询主要用于连表查询,一共有三个场景,一个多、多对多、一对一,如下:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 综上,如果是一对多和一对一关系下,都是一个表的一个外键字段,关系到一个表的主键字段
  • 多对多一般都需要第三张表来进行信息对应。

3.2 连接概述

-- 这种多表查询,会返回两张表的笛卡尔积,就是两个表连接的所有数,即很多不相关数据,原因如下:
select * from table_name1,table_name2;

在这里插入图片描述

  • 也就是说,不加筛选条件的连接查询,会返回笛卡尔积类型的全部数据,笛卡尔积可以去百度一下,这里不赘述,简单来说就是会有很多不相关数据。
  • 下面用一张图简单介绍一下连接查询的分类:

在这里插入图片描述

3.3 内连接

内连接就是返回两张表的交集数据。内连接分为显式内连接隐式内连接两种。

3.3.1 隐式内连接
-- 就是通过where进行对应字段的等值匹配,如下举例
select * from emp , dept where emp.id = dept.id
  • 相对而言,隐式连接好理解好书写,语法简单,担心的点较少。但是显式连接可以减少字段的扫描,有更快的执行速度。这种速度优势在3张或更多表连接时比较明显。因为隐式内连接是先将两张表拼接在一起,然后再通过where筛选出符合条件的数据,而显式内连接则是通过条件筛选匹配,符合条件的数据才返回到结果集。
3.3.2 显式内连接

使用inner join关键字。表A inner join 表B on 连接条件。

select * from emp inner join dept on emp.id = dept.id;
select * from emp join dept on emp.id = dept.id; -- inner关键字可以省略,效果一样

3.4 外连接

外连接主要分为左外连接和右外连接,左外连接就是查询左表的全部数据两张表的交集数据,右外连接则是查询右表的全部数据两张表的交集数据

  • 关键字是:left outer joinright outer join(outer可以省略,如下例子)
-- 左外连接
select * from table1 left outer join table2 on table1.xxx = table2.xxx; -- # outer可以省略
select * from table1 left join table2 on table1.xxx = table2.xxx;-- 右外连接
select * from table1 right join table2 on table1.xxx = table2.xxx
  • 实际开发中,左外连接比较多,因为右外连接能通过左外连接改写, 即更改表的顺序即可,如下
select * from table1 right join table2 on table1.xxx = table2.xxx;
-- 更改两个表的位置即可select * from table2 left join table1 on table1.xxx = table2.xxx;

3.5 自查询

自查询就是同一张表,自己对自己进行连表查询。以下是一个应用场景:

  • 员工表包含上级领导和普通员工**(因为领导也是员工,普通员工也是员工,他们的信息数据都放在员工表)**,有一个字段记录该行数据员工的上级领导id,如果我需要查询该员工的完整信息(包括其上级领导),那么我需要对自己进行连表查询,获得完整数据。
  • 自查询一个关键点就是,一定要为表取别名
select * from table_name table1, table_name table2 where table1.xxx = table2.xxx;

在这里插入图片描述

3.6 联合查询

联合查询就是把两个相同字段的返回结果进行合并。(前提:两个表的字段名称数据类型字段数目都需要一致,否则会报错)

  • 关键字:union 和 union all
select * from table1
union
select * from table2
  • union all会直接将数据合并在一起,不会去重
  • union 则会将重复数据去除

四、子查询

子查询就是嵌套在查询语句里面的查询,后面可以跟着理解。

4.1 标量子查询

标量子查询返回值就是一个标量,一个固定的单个值。为了后面更好理解,后面采用实际SQL语句进行举例。

-- 例如我需要查询张三的生日,查询语句如下,birthday是字段名,emp是表名
select birthday from emp where name = '张三';-- 场景:我们需要查询员工里,所有比张三小的员工,那么我们需要知道张三的出生日期,然后才能进行比较(这里拓展:日期比较能使用大于号比较)-- 如果不使用子查询,我们需要先查询出张三的生日,然后用这个查询出来的值再进行一次SQL查询
select birthday from emp where name = '张三'; -- 例如返回值是2002-11-11
select * from emp where birthday > '2002-11-11';-- 使用子查询,可以简写如下,因为子查询的返回结果是一个标量,那么就是一个值,可以进行比较
select * from emp where birthday > (select birthday from emp where name = '张三');

4.2 单行子查询

行子查询,就是返回值不再是一个单个值,而是一行数据,拥有多个值

  • 通常用于多字段值比较
-- 应用场景:查询员工表里面和张三工资和直系领导一样的员工,emp是表面,money是工资字段
-- manager_id是直系领导id
-- 拓展:这个可以用括号进行多字段值比较select * from emp where(money, mangager_id) = (select money , manager_id from emp where name = '张三');

4.3 单列子查询

列子查询,就是返回值是一列多行

  • 通常用于比较判断,判断某某字段是否在这个范围
-- 应用场景:查询员工表中,比研发部门所有员工工资高的员工,emp是表面,money是工资字段
-- dept_id是部门id,dept_id = 1代指研发部的部门id
select * from emp where money > all(select money from emp where dept_id = 1);
  • 这里介绍一下另外的比较关键字

在这里插入图片描述

4.4 多行多列子查询

多行多列子查询,就是返回值结果像一张表的数据,有多行和多列。

  • 应用场景:可以把这个查询结果当作一张表,然后和其他表进行连接查询

在这里插入图片描述

总结

我自己当时学习是有很多子查询练习,题目和建表语句如下:

在这里插入图片描述

  • 建表语句
-- 部门表dept
create table dept(
id int auto_increment comment 'id' primary key,
name varchar(60) not null comment '部门名称'
)comment '部门表';insert into dept(id,name)
values(1,'研发部'),(2,'市场部'),(3,'财务部'),(4,'销售部'),(5,'总经办');create table emp(
id int auto_increment comment 'ID' primary key,
name varchar(50) not null comment '姓名',
age int comment '年龄',
job varchar(20) comment '职位',
salary int comment '薪资',
entrydate date comment '入职时间',
managerid int comment '直属领导id',
dept_id int comment '部门id'
)comment '员工表';insert into emp(id,name,age,job,salary,entrydate,managerid,dept_id)
values
(1,'金庸',66,'总裁',20000,'2000-01-01',null,5),
(2,'张无忌',20,'项目经理',12500,'2005-12-05',1,1),
(3,'杨逍',33,'开发',8400,'2000-11-03',2,1),
(4,'韦一笑',48,'开发',11000,'2002-02-05',2,1),
(5,'常遇春',43,'开发',10500,'2004-09-07',3,1),
(6,'小昭',19,'程序员鼓励师',6600,'2004-10-12',2,1);create table salgrade(
grade int,
losal int,
hisal int
) comment '薪资等级表';insert into salgrade values (1,0,3000);
insert into salgrade values (2,3001,5000);
insert into salgrade values (3,5001,8000);
insert into salgrade values (4,8001,10000);
insert into salgrade values (5,10001,15000);
insert into salgrade values (6,15001,20000);
insert into salgrade values (7,20001,25000);
insert into salgrade values (8,25001,30000);
  • 以下是我自己的写法,可以参考,答案不唯一,结果和思路正确即可
-- no.1
SELECT e.name,e.age,e.job,d.name FROM emp e INNER JOIN dept d ON e.dept_id=d.id;-- no.2
SELECT e.name,e.age,e.job,d.name FROM emp e INNER JOIN dept d ON e.dept_id=d.id WHERE e.age <30;-- no.3
SELECT DISTINCT d.id,d.`name` FROM emp e INNER JOIN dept d ON e.dept_id = d.id;-- no.4
-- 查询大于40岁的员工
SELECT * FROM emp WHERE age > 40;SELECT * FROM emp LEFT JOIN dept on emp.dept_id = dept.id WHERE emp.age >40;-- no.5
-- 由于员工中的工资字段关联于工资等级表的最大最小值SELECT e.*,s.grade FROM emp e,salgrade s WHERE e.salary >= s.losal and e.salary <= s.hisal;-- no.6
-- 查询研发部的员工id
SELECT id FROM dept WHERE `name` = '研发部';SELECT e.*,s.grade FROM emp e,salgrade s WHERE e.dept_id in (SELECT id FROM dept WHERE `name` = '研发部') and e.salary >= s.losal and e.salary <= s.hisal;-- no.7
SELECT AVG(salary) from emp,dept WHERE emp.dept_id = dept.id and dept.`name`='研发部';-- no.8
SELECT salary FROM emp WHERE `name`='杨逍';SELECT * FROM emp WHERE salary > (SELECT salary FROM emp WHERE `name`='杨逍');-- no.9
SELECT AVG(salary) FROM emp;SELECT * FROM emp WHERE salary > (SELECT AVG(salary) FROM emp);-- no.10
-- 查询本部门的平均薪资
SELECT dept_id,AVG(salary) as avg_money FROM emp GROUP BY dept_id;SELECT * FROM emp,(SELECT dept_id,AVG(salary) as avg_money FROM emp GROUP BY dept_id)as s WHERE emp.dept_id = s.dept_id and emp.salary <= s.avg_money;-- no.11
SELECT COUNT(*),dept.`name` FROM emp , dept  where emp.dept_id = dept.id GROUP BY emp.dept_id ;-- no.11 第二种写法
-- 查询指定id的部门人数
SELECT COUNT(*) FROM emp where dept_id =2;SELECT id , name, (SELECT COUNT(*) FROM emp where dept_id = dept.id) FROM dept ;

五、事务

数据是一系列操作的集合,不可分割的整体,要么全部成功,要么都失败!

5.1 开启事务

  • 方式一:更改全局设定
SELECT @@autocommit; -- 查询事务是否开启,1表示自动提交(不开启事务)set @@autocommit=0; -- 开启事务sql语句commit;	-- SQL都执行成功,可以选择提交事务rollback; 	-- 如果SQL失败,可以选择回滚事务,也就是前面没有commit提交的SQL失效
  • 方式二:手动设置,仅对当前控制台生效
start transaction  / begin; -- 两个语句都行,个人使用begin比较多sql语句commit;

5.2 ACID四大特性

  • 原子性:事务是不可分割的最小操作单元,要么都成功,要么都失败
  • 一致性:事务完成前后的数据是一致的
  • 隔离性:两个事务是有隔离级别的,互不影响
  • 永久性:事务一旦提交或者回滚,他的数据更改是永久性的
http://www.xdnf.cn/news/369307.html

相关文章:

  • 【基于 LangChain 的异步天气查询3】OpenWeather实现实时天气查询
  • 离线化 Service Worker
  • HTTP、HTTPS、SSH区别以及如何使用ssh-keygen生成密钥对
  • 【C++】红黑树
  • Flink和Spark的选型
  • 从父类到子类:C++ 继承的奇妙旅程(2)
  • 【现代深度学习技术】注意力机制04:Bahdanau注意力
  • SwarmUI:基于.Net开发的开源AI 图像生成 Web 用户界面系统
  • GPT-4o, GPT 4.5, GPT 4.1, O3, O4-mini等模型的区别与联系
  • n8n系列(5):LangChain与大语言模型应用
  • Vue3 怎么在ElMessage消息提示组件中添加自定义icon图标
  • 【 Redis | 实战篇 缓存 】
  • VS小技巧:如何在一个项目中添加其他项目
  • 电位器如何接入西门子PLC的模拟量输入
  • 01 dnsmasq 中 dns服务
  • 【大模型面试每日一题】Day 13:数据并行与模型并行的区别是什么?ZeRO优化器如何结合二者?
  • 背单词软件开发英语App英语提分宝超级单词表,河南数匠软件开发
  • PCBA是电子设备的核心大脑!
  • node提示node:events:495 throw er解决方法
  • C语言编程--19.括号生成
  • 手动修改uart16550的FIFO深度?
  • STM32F103VE 三种低功耗模式
  • CN3791 锂电池充电芯片详解及电路设计要点-国产芯片
  • java-多态
  • 机舱巡飞平台技术要点突破点详解!
  • 流式渲染 Streaming SSR
  • deep seek简介和解析
  • BERT模型讲解
  • 【C语言指针超详解(三)】--数组名的理解,一维数组传参的本质,冒泡排序,二级指针,指针数组
  • 开平机:技术深水区与产业变革的融合突破