MySQL数据库DQL

写在前面


大家好,我是一溪风月🥸,一名前端程序员,在上篇文章,我们学习MySQL数据库中的DML语句,这篇文章我们将学习以下MySQL中更加重要的一个内容,DQL语句,也就是MySQL的查询语句,好了,废话不多说让我们开始今天的学习吧~

一.什么是DQL语句


DQL全称是Data Query Language 也就是数据库查询语言,用于从一个或者多个表中检索选中的行,查询的格式如下:

二.准备数据


在进行基础的查询之前我们先来准备一张表

js 复制代码
CREATE TABLE IF NOT EXISTS `products` (
 id INT PRIMARY KEY AUTO_INCREMENT,
 brand VARCHAR(20),
 title VARCHAR(100) NOT NULL,
 price DOUBLE NOT NULL,
 score DECIMAL(2,1),
 voteCnt INT,
 url VARCHAR(100),
 pid INT
 );

然后我们需要插入数据,我们直接通过mysql2来将测试数据进行导入,如果你暂时不理解这些代码,放心等我后边的文章再来介绍,暂时先进行使用,我们需要通过vscode将这个代码进行执行。

js 复制代码
const mysql= require('mysql2');
 const connection = mysql.createConnection({
 host: 'localhost',
 port: 3306,
 user: 'root',
 password: 'root',
 database: 'coderhub'
 });
 const statement = `INSERT INTO products SET ?;`
 const phoneJson= require('./phone.json');
 for (let phone of phoneJson) {
 connection.query(statement, phone);
 }

相关json文件放在了github,地址为:phone.json 然后我们来执行一下这个代码,然后我们就会看到数据都被初始化到数据库里面了,我们就可以根据这些数据来做查询了。

三.基本查询


查询所有的数据并显示所有的字段

js 复制代码
SELECT * FROM `products`;

查询title,brand,price

js 复制代码
SELECT title,brand,price FROM `products`;

我们也可以给字段起别名,别名一般在多张表或者给客户端返回对应的key时候会使用到

js 复制代码
SELECT title as t,brand as b,price as p FROM `products`;

四.where条件的查询


在开发中我们往往希望根据条件进行查询数据,这个时候我们要使用条件查询,条件查询我们会使用where来进行

where的比较运算符

js 复制代码
# 查询价格小于1000的手机
SELECT * FROM `products` WHERE price < 1000;
# 查询价格大于等于2000的手机
SELECT * FROM `products` WHERE price >= 2000;
# 价格等于3399的手机
SELECT * FROM `products` WHERE price = 3399;
# 查询价格不等于3399的手机
SELECT * FROM `products` WHERE price != 3399;
# 查询华为品牌的手机
SELECT * FROM `products` WHERE `brand` = '华为';

where的 逻辑运算符

js 复制代码
# 查询品牌是华为,并且小于2000的手机
SELECT * FROM `products` WHERE `brand` = '华为' AND `price` < 2000;
# 查询1000到2000的手机(不包含1000和2000)
SELECT * FROM `products` WHERE `price` > 1000 AND `price` < 2000;
# 查询所有华为手机或者价格小于1000的手机
SELECT * FROM `products` WHERE `price` < 1000 AND `brand` = '华为';
# 查询1000到2000的手机(包含1000到2000)
SELECT * FROM `products` WHERE `price` BETWEEN 1000 AND 2000;
# 查看多个结果中的一个
SELECT * FROM `products` WHERE `brand` IN ('小米','华为');

模糊查询使用LIKE关键字,结合两个特殊符号:

  • %表示匹配任意个任意字符
  • _表示匹配一个任意字符
js 复制代码
# 查询所有以v开头的title
SELECT * FROM `products` WHERE `title` LIKE 'v%';
# 查询带M的title
SELECT * FROM `products` WHERE `title` LIKE '%M%';
# 查询带M的数据比较是第三个字符
SELECT * FROM `products` WHERE `title` LIKE '__M%';

五.查询结果排序


有的时候当我们查询到结果的时候,我们希望结果按照某种方式进行排序,这个时候使用的是order by

  • ASC:升序排序
  • DESC:降序排序
js 复制代码
# 对查询到的品牌为华为的并且价格小于1000的手机按照价格进行升序排序
SELECT * FROM `products` WHERE `brand` = '华为' AND `price` < 1000 ORDER BY price ASC;

六.分页查询


当数据库的数据非常多的时,一次性查询到所有的结果是不太现实的:

  • 在真实的项目,我们都会要求用户传入offset,limit或者page等字段。
  • 它们的目的是让我们可以在数据库中进行分页查询。
  • 它的用法有[LIMIT {[offset,] row_count | row_count OFFSET offset}]
js 复制代码
# 查询前30条数据
SELECT * FROM `products` LIMIT 30 OFFSET 0;
# 查询31-60条数据
SELECT * FROM `products` LIMIT 30 OFFSET 30;
# 查询61-90条数据(另外一种写法:offset, row_count)
SELECT * FROM `products` LIMIT 90,30;

七.聚合函数


聚合函数表示对值的集合进行操作的组(集合)函数

js 复制代码
# 华为手机价格的平均值
SELECT AVG(price),brand FROM `products` WHERE `brand`= '华为';
# 计算所有手机的平均分
SELECT AVG(price) FROM `products`;
# 手机中的最高分和最低分
SELECT MAX(score) FROM `products`;
SELECT MIN(score) FROM `products`;
# 计算总投票人数
SELECT COUNT(voteCnt) FROM `products`;
# 计算所有条目的数量
SELECT COUNT(*) FROM `products`;
# 华为手机的个数
SELECT COUNT(*) FROM `products` WHERE `brand` = '华为';

八.认识Group By


事实上聚合函数相当于默认将所有的数据分成了一组

  • 我们前面是使用AVG还是MAX,都是将所有结果当成一组来进行计算。
  • 那么如果我们希望划分多组:比如华为,苹果,小米等手机分别的平均价格,应该怎么做哪?
  • 这个时候我们应该使用Group By。

Group By通常和聚合函数一起使用

  • 表示我们先对数据进行分组,再对每一组数据,进行聚合函数的计算。

那么我们先来提一个需求,然后根据这个需求来实现一下

根据品牌进行分组,计算各个品牌中的商品个数,平均价格,也包括最高价格,最低价格,平均评分。

js 复制代码
SELECT COUNT(brand), ROUND(AVG(price),2) AS priceAvg,MIN(price) AS minPrice,MAX(price) AS maxPrice ,ROUND(AVG(score),2) avgScore FROM `products` GROUP BY `brand`; 

九.Group By的约束条件


如果我们还希望给Group By查询到的结果添加一些约束,那么我们还可以使用HAVING,比如我们希望筛选出平均价格在4000以下,并且平均分在7以上的品牌。

js 复制代码
SELECT COUNT(brand), ROUND(AVG(price),2) AS priceAvg,MIN(price) AS minPrice,MAX(price) AS maxPrice ,ROUND(AVG(score),2) AS avgScore FROM `products` GROUP BY `brand` HAVING priceAvg < 4000 AND avgScore > 7; 

十.创建多张表


假如我们在上面的商品表中,对应的品牌还包含其他信息,比如品牌的官网,品牌的世界排名,品牌的市值等等,如果我们直接在商品中去体现品牌相关的信息,会存在一些问题。

  • 一方面,products表中应该表示的都是商品相关的数据,应该又另外一张表来表示brand的数据。
  • 另一方面,多个商品使用的品牌是一致时,会存在大量的冗余数据。

所以,我们可以将所有的品牌数据,单独放到一张表中,创建一张品牌的表:

js 复制代码
CREATE TABLE IF NOT EXISTS `brand`(
 id INT PRIMARY KEY AUTO_INCREMENT,
 name VARCHAR(20) NOT NULL,
 website VARCHAR(100),
 worldRank INT
 );

然后我们来插入几条模拟数据

js 复制代码
INSERT INTO `brand` (name, website, worldRank) VALUES ('华为', 'www.huawei.com', 1);
 INSERT INTO `brand` (name, website, worldRank) VALUES ('小米', 'www.mi.com', 10);
 INSERT INTO `brand` (name, website, worldRank) VALUES ('苹果', 'www.apple.com', 5);
 INSERT INTO `brand` (name, website, worldRank) VALUES ('oppo', 'www.oppo.com', 15);
 INSERT INTO `brand` (name, website, worldRank) VALUES ('京东', 'www.jd.com', 3);
 INSERT INTO `brand` (name, website, worldRank) VALUES ('Google', 'www.google.com', 8);

十一.创建外键


将两张表联系起来,我们可以将products中的brand_id关联到brand中的id,如果是创建表添加外键约束,我们需要在创建表的()最后添加如下语句;

js 复制代码
FOREIGN KEY (brand_id) REFERENCES brand(id);

如果表已经创建好了,我们需要额外的添加外键

js 复制代码
ALTER TABLE `products` ADD `brand_id` INT;
ALTER TABLE `products` ADD FOREIGN KEY (brand_id) REFERENCES brand(id);

现在我们可以将products中的brand_id关联到brand中的id的值。

js 复制代码
UPDATE `products` SET `brand_id` = 1 WHERE `brand` = '华为';
UPDATE `products` SET `brand_id` = 4 WHERE `brand` = 'OPPO';
UPDATE `products` SET `brand_id` = 3 WHERE `brand` = '苹果';
UPDATE `products` SET `brand_id` = 2 WHERE `brand` = '小米';

然后我们就可以看到新增的外键有数据了

十二.外键存在时的更新和删除


如果products中引用的外键被更新了或者删除了,这个时候会出现什么情况呢? 我们来进行一个更新操作,比如将华为的id更新为100。

js 复制代码
UPDATE `brand` SET id = 100 WHERE id = 1;

我们发现是无法修改的,因为两个表之间有关联关系,其实这种情况非常容易理解。

十三.如何进行更新?


但是如果我们希望更新哪?我们需要修改on delete或者on update的值,我们可以给更新或者删除时设置几个值:

  • RESTRICT(默认属性):当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话会报错,不允许更新或者删除。
  • NO ACTION:和RESTRICT 是一致的,是在SQL标准中定义的。
  • CASCADE:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话更新,那么会更新对应的记录,删除,那么关联的记录会被一起删除掉。
  • SET NULL:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话,将对应的值设置为NULL。
js 复制代码
SHOW CREATE TABLE `products`;
ALTER TABLE `products` DROP FOREIGN KEY products_ibfk_1;
ALTER TABLE `products` ADD FOREIGN KEY (brand_id) REFERENCES brand(id) 
ON UPDATE CASCADE 
ON DELETE CASCADE;

十四.什么是多表查询


如果我们希望查询到产品的同时,显示对应的品牌相关的信息,因为数据是存放在两张表中,所以这个时候就需要进行多表查询,如果我们直接通过查询语句希望在多张表中查询到数据,这个时候是什么效果呢?

js 复制代码
SELECT * FROM `products`,`brand`;

我们会发现数据被组合到了一起,并且数据量非常的大,第一张表中每一个条数据,都会和第二张表中的每一条数据结合一次,这个结果我们称之为笛卡尔乘积,也称之为直积,表示为X*Y。

但是事实上很多数据是没有意义的比如华为和苹果、小米的品牌结合起来的数据就是没有意义的,我们可不可以进行筛选呢?使用where来进行筛选,这个表示查询到笛卡尔乘积后的结果中,符合products.brand_id = brand.id条件的数据过滤出来;

js 复制代码
SELECT * FROM `products`, `brand` WHERE `products`.brand_id = `brand`.id;

但是这种效果依然不是我们想要的,因为可能有些手机品牌在其他的表中对应的关联id并不存在,其实这种情况,这种方式也并不能满足我们的需求。

十五.多表之间的连接


左连接:如果我们希望获取到的是左边所有的数据(以左表为主)[重点]

  • 这个时候就表示无论左边的表是否有对应的brand_id的值对应右边表的id,左边的数据都会被查询出来
  • 这个也是开发中使用最多的情况,它的完整写法是LEFT [OUTER] JOIN,但是OUTER可以省略的。
js 复制代码
SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id;

我们发现发现连接查询并且通过一定的条件过滤之后,有很多NULL的数据,我们将为NULL的查询出来,其实我们查询就是左表和右边没有交集的部分。

js 复制代码
SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id WHERE `brand`.id IS NULL;

右连接:如果我们希望获取到的是右边所有的数据(以由表为主)[了解]

  • 这个时候就表示无论左边的表中的brand_id是否有和右边表中的id对应,右边的数据都会被查询出来;
  • 右连接在开发中没有左连接常用,它的完整写法是RIGHT [OUTER] JOIN,但是OUTER可以省略的。
js 复制代码
SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id;

我们会发现右连接将谷歌和京东的数据也查询出来了,但是其实右连接我们一般不会使用

js 复制代码
SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id WHERE `products`.id IS NULL;

内连接: 事实上内连接是表示左边的表和右边的表都有对应的数据关联 [重点]

  • 内连接在开发中偶尔也会有一些场景使用,看自己的场景。
  • 内连接有其他的写法:CROSS JOIN或者JOIN都可以
js 复制代码
SELECT * FROM `products` INNER JOIN `brand` ON `products`.id = `brand`.id;

全连接: SQL 规范中全连接是使用FULL JOIN,但是 MySQL 中并没有对它的支持,我们需要使用UNION 来实现[了解]

js 复制代码
(SELECT * FROM `products` LEFT JOIN `brand` ON `products`.id = `brand`.id) 
 UNION
(SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.id = `brand`.id);

然后我们再来过滤以下中间没有交集的数据。

js 复制代码
(SELECT * FROM `products` LEFT JOIN `brand` ON `products`.id = `brand`.id WHERE `brand`.id IS NULL) 
UNION
(SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.id = `brand`.id  WHERE `products`.id IS NULL);

十六.多对多关系数据的准备


在开发中我们也可能会遇到多对多的关系,比如,比如学生可以选择多门课程,一个课程可以被多个学生选择,那么这种情况在开发中应该如何处理哪?我们先建立两张表来演示下:

js 复制代码
# 创建学生表
CREATE TABLE IF NOT EXISTS `students`(
 id INT PRIMARY KEY AUTO_INCREMENT,
 name VARCHAR(20) NOT NULL,
 age INT
 );


# 创建课程表
CREATE TABLE IF NOT EXISTS `courses`(
 id INT PRIMARY KEY AUTO_INCREMENT,
 name VARCHAR(20) NOT NULL,
 price DOUBLE NOT NULL
 );

然后插入一些数据

js 复制代码
INSERT INTO `students` (name, age) VALUES('why', 18);
INSERT INTO `students` (name, age) VALUES('tom', 22);
INSERT INTO `students` (name, age) VALUES('lilei', 25);
INSERT INTO `students` (name, age) VALUES('lucy', 16);
INSERT INTO `students` (name, age) VALUES('lily', 20);

INSERT INTO `courses` (name, price) VALUES ('英语', 100);
INSERT INTO `courses` (name, price) VALUES ('语文', 666);
INSERT INTO `courses` (name, price) VALUES ('数学', 888);
INSERT INTO `courses` (name, price) VALUES ('历史', 80);

十七.创建关系表


在处理多对多的关系的时候我们一般会创建一个中间表来联系两张表,我们创建的这张表叫做关系表

js 复制代码
CREATE TABLE IF NOT EXISTS `students_select_courses`(
 id INT PRIMARY KEY AUTO_INCREMENT,
 student_id INT NOT NULL,
 course_id INT NOT NULL,
 FOREIGN KEY (student_id) REFERENCES students(id) ON UPDATE CASCADE,
 FOREIGN KEY (course_id) REFERENCES courses(id) ON UPDATE CASCADE
 );

然后我们给这张表插入数据

js 复制代码
# why 选修了英文和数学
INSERT INTO `students_select_courses` (student_id, course_id) VALUES (1, 1);
INSERT INTO `students_select_courses` (student_id, course_id) VALUES (1, 3);
 # lilei选修了语文和数学和历史
INSERT INTO `students_select_courses` (student_id, course_id) VALUES (3, 2);
INSERT INTO `students_select_courses` (student_id, course_id) VALUES (3, 3);
INSERT INTO `students_select_courses` (student_id, course_id) VALUES (3, 4);

十八.查询多对多的数据[难点]


在上述的查询中,我们往往在一张表里面不同的字段之间的关系是一对一的关系,但是在两张表里面可能就是一对多的关系,比如商标表中的一个id在价格表中可能有很多brandId。

但是其实最复杂的是多对多的关系,比如在学校,一个学生可以选择多门课程,一门课程也能被多个学生选择,这种关系就是常见的多对多的关系,我们处理多对多的关系往往是按照如下关系解决。

这样我们就可以通过关系表中的学生id来查询他选择了哪些课程,也可以通过课程id来看下有哪些学生选择,这样就解决了多对多的关系问题,其实这种思想就是一种分层架构。

查询多条数据

js 复制代码
# 查询所有学生选择的所有课程
SELECT
 * 
 FROM `students` 
 JOIN `students_select_courses` ON `students`.id = `students_select_courses`.student_id
 JOIN `courses` ON `courses`.id = `students_select_courses`.course_id;
 
 # 查询所有学生的选课情况
 SELECT
 * 
 FROM `students` 
 LEFT JOIN `students_select_courses` ON `students`.id = `students_select_courses`.student_id
 LEFT JOIN `courses` ON `courses`.id = `students_select_courses`.course_id;
 
 # why同学选择了哪些课程(必须使用左连接)
 SELECT
 * 
 FROM `students` 
 LEFT JOIN `students_select_courses` ON `students`.id = `students_select_courses`.student_id
 LEFT JOIN `courses` ON `courses`.id = `students_select_courses`.course_id
 WHERE students.`name` = 'why';
 
 # 哪些学生是没有选课的
 SELECT
 * 
 FROM `students` 
 LEFT JOIN `students_select_courses` ON `students`.id = `students_select_courses`.student_id
 LEFT JOIN `courses` ON `courses`.id = `students_select_courses`.course_id
 WHERE `courses`.id IS NULL;
 
 # 查询哪些课程没有被学生选择
 SELECT
 * 
 FROM `students` 
 RIGHT JOIN `students_select_courses` ON `students`.id = `students_select_courses`.student_id
 RIGHT JOIN `courses` ON `courses`.id = `students_select_courses`.course_id
 WHERE `students`.id IS NULL;

十九.总结


这篇文章到这里就结束了🌸,这篇文章我们主要讲解了MySQL的查询语句,包括基本的查询和比较复杂的多对多的查询,以及表的关联关系,这些东西都非常的重要,这些内容是我们在开发服务器时候的经常要使用的~

相关推荐
巴巴_羊41 分钟前
React Redux
开发语言·前端·javascript
Mintopia42 分钟前
Node.js 中的this
前端·javascript·node.js
Mike_jia43 分钟前
一篇文章带你了解一款强大的开源跨平台远程桌面管理工具---XPipe
前端·开源
._Ha!n.1 小时前
React基础知识一
前端·react.js
Mintopia1 小时前
深入理解 Three.js 中 Shader 的使用及示例
前端·javascript·three.js
睡觉zzz1 小时前
React写ai聊天对话,如何实现聊天makedown输出转化
前端·人工智能·react.js
iOS阿玮1 小时前
截止目前已有15.6w应用惨遭下架,你的应用还好么?
前端·app·apple
半旧5181 小时前
【重构谷粒商城12】npm快速入门
前端·重构·npm
snakeshe10101 小时前
剖析 React Commit 阶段:详解工作流程与三大核心模块
前端
爱生活的前端狗1 小时前
一次大批量处理视频文件的性能优化记录
前端·javascript·vue.js