MySQL

___软件系统需要存放大量的数据 这些数据通常是非常复杂和庞大的

文件系统的缺点:

  • 很难以合适的方式组织数据
  • 很难进行数据共享 比如一个数据库需要为多个程序服务
  • 对数据进行增删改查中的复杂操作 保证单操作的原子性

常见数据库

  • 关系型数据库: MySQL、Oracle、DB2、SQL Server、Postgre SQL等
    • 关系型数据库通常我们会创建很多个二维数据表;
    • 数据表之间相互关联起来,形成一对一、一对多、多对对等关系;
    • 之后可以利用SQL语句在多张表中查询我们所需的数据;
    • 支持事务,对数据的访问更加的安全;
  • 非关系型数据库:MongoDB、Redis、Memcached、HBse等;
    • 非关系型数据库的英文其实是Not only SQL,也简称为NoSQL;
    • 非关系型数据库比较简单一些,存储数据也会更加自由(甚至我们可以直接将一个复杂的json对象直接塞入到数据库中)
    • NoSQL是基于Key-Value的对应关系,并且查询的过程中不需要经过SQL解析,所以性能更高;
    • NoSQL通常不支持事务,需要在自己的程序中来保证一些原子性的操作;
    • 比较常用的用到非关系型数据库的,在爬取大量的数据进行存储时,会比较常见;

认识MySQL

MySQL是一个关系型数据库,其实本质上就是一款软件、一个程序:

  • 这个程序中管理着多个数据库;

  • 每个数据库中可以有多张表;

  • 每个表中可以有多条数据;

起步

下载:https://dev.mysql.com/downloads/mysql/

————如果下载慢 复制下载链接使用迅雷下载 快的意想不到

服务->启动MySQL80

MySQL的连接操作

第一次执行mysql--version 会找不到指令

所以添加环境变量

  • window中:
    • 打开电脑环境变量配置 然后在系统配置中找到path 将mysql可执行地址放到path中就可以了 一般默认C:\Program Files\MySQL\MySQL Server 8.0\bin

在终端中连接mysql

  • mysql -uroot -p密码

  • 或者 mysql -uroot -p 回车输入密码

  • 使用 gitbash 来连接数据库要执行该指令 winpty mysql -uroot -p

查看默认数据库 show databases

  • infomation_schema:信息数据库,其中包括MySQL在维护的其他数据库、表、列、访问权限等信息;
  • performance_schema:性能数据库,记录着MySQL Server数据库引擎在运行 过程中的一些资源消耗相关的信息;
  • mysql:用于存储数据库管理者的用户信息、权限信息以及一些日志信息等;
  • sys:相当于是一个简易版的performance_schema,将性能数据库中的数据汇总成更容易理解的形式;

操作数据库

创建数据库

  • 创建数据库 create database coderhub;

  • 使用数据库use coderhub;

  • 创建一张表

    1
    2
    3
    4
    5
    create table users(
    name varchar(20),
    age int,
    height double
    );
  • 插入数据 insert into users (name, age, height) values ('hyyp', 20, 1.88);

  • 查询表中全部数据 select * from users

GUI工具

用 Navicat 就完事了 施展传统艺能

SQL语句

___和数据库沟通的语言 结构化查询语言 是Structured Query Language(SQL)

SQL语句的常用规范

  • 通常关键字是大写的,比如CREATE、TABLE、SHOW等等;
  • 一条语句结束后,需要以;结尾;
  • 如果遇到关键字作为表明或者字段名称,可以使用``包裹;

分类

常见的SQL语句我们可以分成四类:

  • DDL(Data Definition Language):数据定义语言;
    • 可以通过DDL语句对数据库或者进行:创建、删除、修改等操作;
  • DML(Data Manipulation Language):数据操作语言;
    • 可以通过DML语句对 数据进行:添加、删除、修改等操作;
  • DQL(Data Query Language):数据查询语言;
    • 可以通过DQL从数据库中查询记录;(重点
  • DCL(Data Control Language):数据控制语言;
    • 对数据库、表格的权限进行相关访问控制操作;

DDL语句

数据库操作

  • 创建数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 查看所有的数据库
    SHOW DATABASES;

    # 选择某个数据库
    USE coderhub;

    # 查看当前使用的数据库
    SELECT DATABASE();

    # 新建数据库
    -- CREATE DATABASE hyp;
    -- CREATE DATABASE IF NOT EXISTS hyp;
    CREATE DATABASE IF NOT EXISTS peng DEFAULT CHARACTER SET utf8mb4
    COLLATE utf8mb4_0900_ai_ci;
  • 删除数据库

1
2
# 删除数据库
DROP DATABASE IF EXISTS hyp;
  • 修改数据库编码
1
2
3
# 修改数据库的编码
ALTER DATABASE peng CHARACTER SET = utf8
COLLATE=utf8_unicode_ci;

数据表的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看所有表
SHOW TABLES;

# 新建表
CREATE TABLE IF NOT EXISTS `students` (
`name` VARCHAR(10),
`age` int,
`score` int
);

# 删除表
DROP TABLE IF EXISTS `emole`;

#查看表的结构
DESC students;

SQL的数据类型

___MySQL支持的数据类型有:数字类型,日期和时间类型,字符串(字符和字节)类型,空间类型和 JSON数据类型。

数字类型

MySQL的数字类型有很多:

  • 整数数字类型:INTEGER,INT,SMALLINT,TINYINT,MEDIUMINT,BIGINT;
  • 浮点数字类型:FLOAT,DOUBLE(FLOAT是4个字节,DOUBLE是8个字节);
  • 精确数字类型:DECIMAL,NUMERIC(DECIMAL是NUMERIC的实现形式);
    • DECIMAL(有效数字数的精度,小数点后的位数)

日期类型

YEAR以YYYY格式显示值

  • 范围 1901到2155,和 0000。

DATE类型用于具有日期部分但没有时间部分的值:

  • DATE以格式YYYY-MM-DD显示值 ;
  • 支持的范围是 ‘1000-01-01’ 到 ‘9999-12-31’;

DATETIME类型用于包含日期和时间部分的值

  • DATETIME以格式’YYYY-MM-DD hh:mm:ss’显示值
  • 支持的范围是1000-01-01 00:00:00到9999-12-31 23:59:59;

TIMESTAMP数据类型被用于同时包含日期和时间部分的值:

  • TIMESTAMP以格式’YYYY-MM-DD hh:mm:ss’显示值
  • 但是它的范围是UTC的时间范围:’1970-01-01 00:00:01’到’2038-01-19 03:14:07’;

DATETIME或TIMESTAMP 值可以包括在高达微秒(6位)精度的后小数秒一部分

字符串类型

  • CHAR类型在创建表时为固定长度,长度可以设置0到255之间的任何值;
    • 在被查询时,会删除后面的空格;
  • VARCHAR类型的值是可变长度的字符串,长度可以指定为0到65535之间的值;(使用比较多)
    • 在被查询时,不会删除后面的空格;
  • BINARY和VARBINARY 类型用于存储二进制字符串,存储的是字节字符串;
  • BLOB用于存储大的二进制类型
  • TEXT用于存储大的字符串类型

表约束

主键:PRIMARY KEY

在一张表中,我们为了区分每一条记录的唯一性,必须有一个字段是永远不会重复,并且不会为空的,这个字段我们通常会将它设置为主键:

主键是表中唯一的索引;

  • 且必须是NOT NULL的,如果没有设置 NOT NULL,那么MySQL也会隐式的设置为NOT NULL;

  • 主键也可以是多列索引,PRIMARY KEY(key_part, …),我们一般称之为联合主键;

  • 建议:开发中主键字段应该是和业务无关的,尽量不要使用业务字段来作为主键

唯一:UNIQUE

  • 某些字段在开发中我们希望是唯一的,不会重复的,比如手机号码、身份证号码等,这个字段我们可以使用UNIQUE来约束
  • 使用UNIQUE约束的字段在表中必须是不同的
  • 对于所有引擎,UNIQUE 索引允许NULL包含的列具有多个值NULL。

不能为空:NOT NULL

  • 某些字段我们要求用户必须插入值,不可以为空,这个时候我们可以使用 NOT NULL 来约束;

默认值:DEFAULT

  • 某些字段我们希望在没有设置值时给予一个默认值,这个时候我们可以使用 DEFAULT来完成

自动递增:AUTO_INCREMENT (一般用在数字类型)

  • 某些字段我们希望不设置值时可以进行递增,比如用户的id,这个时候可以使用AUTO_INCREMENT来完成

创建一个完整的表

1
2
3
4
5
6
7
CREATE TABLE IF NOT EXISTS `hypers`(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
age INT DEFAULT 0,
phoneNum VARCHAR(20) UNIQUE DEFAULT '',
createtime TIMESTAMP
);

修改表

1
2
3
4
5
6
7
8
9
10
#1.修改表的名字
ALTER TABLE `hypers` RENAME TO `ypeng`;
#2.添加一个新的列
ALTER TABLE `ypeng` ADD `updateTime` TIMESTAMP;
#3.修改字段名称
ALTER TABLE `ypeng` CHANGE `phoneNum` `telPhone` VARCHAR(20);
#4.修改字段类型
ALTER TABLE `ypeng` MODIFY `name` VARCHAR(30);
#5.删除某一个字段
ALTER TABLE `ypeng` DROP `age`;
1
2
3
4
#根据一个表结构创建另外一张表
CREATE TABLE `user1` like `ypeng`;
#根据另外一个表中的所有内容创建一个新的表 (只会复制内容)
CREATE TABLE `user2` (SELECT * FROM `ypeng`);

createTime 和 updateTime 可以自动设置值:

1
2
3
ALTER TABLE `ypeng` MODIFY `createTime`     TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE `ypeng` MODIFY `updateTime` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP;

DML语句

插入数据

1
2
3
INSERT INTO `ypeng` VALUES (111,'HYP','4441','2020-11-11','2020-11-22');
INSERT INTO `ypeng` (name,telPhone,createTime,updateTime)
VALUES('shady','11111','2020-12-12','2021-1-1');

删除数据

1
2
3
4
5
6
# 删除数据    
#删除所有数据
DELETE FROM `ypeng`;
#删除符合条件的一条数据
DELETE FROM `ypeng` WHERE id = 111;

更新数据

1
2
3
4
5
#更新数据.
#更新所有数据
UPDATE `ypeng` SET `name` = 'jash',telPhone = '9999';
#更新符合条件的一条数据
UPDATE `ypeng` SET `name` = 'jash',telPhone = '9999' WHERE id=113;

DQL语句

查询表中所有字段以及数据

SELECT * FROM products;

查询指定字段

SELECT title,price FROM products;

对字段结果起一个别名

SELECT title as phoneTitle,price as currentPrice FROM products;

where查询条件

条件判断语句

1
2
3
4
5
6
7
8
9
#价格小于1000的手机
SELECT title,price FROM `products` WHERE price <1000;
#价格等于999的手机
SELECT * FROM `products` WHERE price = 999;
#价格不等于999的手机
SELECT * FROM `products` WHERE price != 999;
SELECT * FROM `products` WHERE price <> 999;
#查询所有的牌子是华为的!
SELECT * FROM `products` WHERE brand = "华为";

逻辑运算语句

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查询1000到2000之间
SELECT * FROM `products` WHERE price >1000 AND price<2000;
SELECT * FROM `products` WHERE price >1000 && price<2000;
#BETWEEN AND包含等于
SELECT * FROM `products` WHERE price BETWEEN 1099 AND 2000;

#价格在5000以上或者品牌是华为!
SELECT * FROM `products` WHERE price >5000 || brand="华为";
#查询某个值为NULL
SELECT * FROM `products` WHERE url is NULL;
#查询某个值不为NULL
SELECT * FROM `products` WHERE url is NOT NULL;

模糊查询

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

  • %表示匹配任意个的任意字符;

  • _表示匹配一个的任意字符;

1
2
3
4
5
6
# 查询所有以v开头的title
SELECT * FROM `products` WHERE title LIKE 'v%';
# 查询带M的title
SELECT * FROM `products` WHERE title LIKE '%M%';
# 查询带M的title必须是第三个字符
SELECT * FROM `products` WHERE title LIKE '__M%';

IN表示取多个值中的其中一个

1
2
3
等价
SELECT * FROM `products` WHERE brand ="华为"||brand="小米"||brand="苹果";
SELECT * FROM `products` WHERE brand IN('华为','小米','苹果');

结果排序

ASC:升序排列;

DESC:降序排列;

1
2
SELECT * FROM `products` WHERE brand IN('华为','小米','苹果') 
ORDER BY price ASC,score DESC;

分页查询

  • [LIMIT {[offset,] row_count | row_count OFFSET offset}]
1
2
3
4
5
# LIMIT limit OFFSET offset;
SELECT * FROM `products` LIMIT 20 OFFSET 0 ;
SELECT * FROM `products` LIMIT 20 OFFSET 20 ;
# Limit offset,limit;
SELECT * FROM `products` LIMIT 40,20;
聚合函数

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

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#1.1求所有手机的价格的总和
SELECT SUM(price) totalPrice FROM `products`;
#求苹果手机的价格总和
SELECT SUM(price) appletotalPrice FROM `products` WHERE `brand` = '苹果';
#求苹果手机平均价格
SELECT AVG(price) FROM `products` WHERE `brand` = '苹果';
#最高手机和最低手机价格
SELECT MAX(price) FROM `products`;
SELECT MIN(price) FROM `products`;

#苹果手机的个数
SELECT COUNT(*) FROM `products` WHERE brand ='苹果';
SELECT COUNT(url) FROM `products` WHERE brand ='华为';

SELECT COUNT(price) FROM `products`;
# 去重
SELECT COUNT(DISTINCT price) FROM `products`;

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

GroupBy

  • GROUP BY通常和聚合函数一起使用:
    • 表示我们先对数据进行分组,再对每一组数据,进行聚合函数的计算;
1
2
以brand分组 计算平均价格 个数 平均评分
SELECT brand,AVG(price),COUNT(*),AVG(score) FROM `products` GROUP BY brand;
  • Group By的约束

    • 使用HAVING关键字 对GroupBy查询到的结果添加一些约束可以使用HAVING

      1
      2
      平均价格大于2000的品牌
      `SELECT brand,AVG(price) avgPrice,COUNT(*),AVG(score) FROM products GROUP BY brand HAVING avgPrice>2000;`
    • 而WHERE是对表进行筛选 比如

    1
    2
    需求:评分大于7.5的手机按照品牌分类求出平均价格
    SELECT brand,AVG(price) FROM `products` WHERE score>7.5 GROUP BY brand;

多张表的创建

商品表中对应的品牌需要包含很多其他的信息 为了防止数据混乱以及冗余 使用单独的一张表来存放品牌的信息

  • 创建品牌(brand)表:
1
2
3
4
5
6
CREATE TABLE IF NOT EXISTS `brand`(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
website VARCHAR(100),
phoneRank INT
);
  • 插入数据
1
2
3
4
5
6
7
8

INSERT INTO `brand` (name,website,phoneRank) VALUES ('苹果','www.apple.com',1);
INSERT INTO `brand` (name,website,phoneRank) VALUES ('华为','www.huawei.com',2);
INSERT INTO `brand` (name,website,phoneRank) VALUES ('小米','www.xiaomi.com',3);
INSERT INTO `brand` (name,website,phoneRank) VALUES ('oppo','www.oppo.com',4);

INSERT INTO `brand` (name,website,phoneRank) VALUES ('moto','www.moto.com',9);
INSERT INTO `brand` (name,website,phoneRank) VALUES ('google','www.google.com',10);

外键

将两张表联系起来,我们可以将products中的brand_id关联到brand中的id:

  • 如果是创建表添加外键约束,我们需要在创建表的()最后添加如下语句;
    • FOREIGN KEY (brand_id) REFERENCES brand(id)
  • 如果是表已经创建好,额外添加外键:
    • ALTER TABLE products ADD FOREIGN KEY (brand_id) REFERENCES brand(id)

关联:

1
2
3
4
5
设置brand_id的值
UPDATE `products` SET `brand_id` = 2 WHERE `brand`='华为';
UPDATE `products` SET `brand_id` = 1 WHERE `brand`='苹果';
UPDATE `products` SET `brand_id` = 3 WHERE `brand`='小米';
UPDATE `products` SET `brand_id` = 4 WHERE `brand`='oppo';

外键存在时更新和删除数据

如果products中引用的外键被更新了或者删除了,这个时候执行代码是报错的

有的时候我们希望可以更新

可以给更新或者删除时设置几个值:

  • RESTRICT(默认属性):当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话会报错的,不允许更新或删除;

  • NO ACTION:和RESTRICT是一致的,是在SQL标准中定义的;

  • CASCADE:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话:

    • 更新:那么会更新对应的记录;

    • 删除:那么关联的记录会被一起删除掉;

  • SET NULL:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话,将对应的值设置为NULL;

修改外键的更新时动作:

  • 查看表结构 SHOW CREATE TABLE products;

    • 可以知道外键的名称是products_ibfk_1
  • 删除之前的外键

    • ALTER TABLE products DROP FOREIGN KEY products_ibfk_1;
  • 添加新的外键,并且设置新的action

    1
    2
    3
    ALTER TABLE `products` ADD FOREIGN KEY (brand_id) 
    REFERENCES brand(id)
    ON UPDATE CASCADE ON DELETE CASCADE;

多表查询

如果我们希望查询到产品的同时,显示对应的品牌相关的信息,因为数据是存放在两张表中,所以这个时候就需要进行多表查询。

默认的多表查询的结果

  • 如果我们直接通过查询语句希望在多张表中查询到数据SELECT * FROM products, brand;

  • 得到的结果第一张表中每一个条数据,都会和第二张表中的每一条数据结合一次 这个结果我们称之为 笛卡尔乘积,也称之为直积,表示为 X*Y

  • 我们可以使用where来筛选

  • SELECT * FROM products, brand WHERE products.brand_id = brand.id;

  • 这个表示查询到笛卡尔乘积后的结果中,符合products.brand_id = brand.id条件的数据过滤出来

  • 但是这种方式在真实开发中一般不做使用

多表之间连接

  • 左连接
  • 如果我们希望获取到的是左边所有的数据(以左表为主):
    • 这个时候就表示无论左边的表是否有对应的brand_id的值对应右边表的id,左边的数据都会被查询出来;
    • 这个也是开发中使用最多的情况,它的完整写法是LEFT [OUTER] JOIN,但是OUTER可以省略的;
1
2
3
4
SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id;
SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id
WHERE brand.id IS NULL;

  • 右连接
  • 如果我们希望获取到的是右边所有的数据(以右表为主)
    • 这个时候就表示无论左边的表中的brand_id是否有和右边表中的id对应,右边的数据都会被查询出来;
    • 右连接在开发中没有左连接常用,它的完整写法是RIGHT [OUTER] JOIN,但是OUTER可以省略的
1
2
3
SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id;
SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id
WHERE products.id IS NULL;
  • 内连接
  • 内连接是表示左边的表和右边的表都有对应的数据关联
1
SELECT * FROM `products` JOIN `brand` ON products.brand_id=brand.id WHERE price =1499;
  • 我们会发现它和之前的下面写法是一样的效果:

    1
    SELECT * FROM `products`, `brand` WHERE `products`.brand_id = `brand`.id;
  • 但是他们代表的含义并不相同:

    • SQL语句一:内连接,代表的是在两张表连接时就会约束数据之间的关系,来决定之后查询的结果;

    • SQL语句二:where条件,代表的是先计算出笛卡尔乘积,在笛卡尔乘积的数据基础之上进行where条件的筛选;

  • 全连接

    1
    2
    3
    4
    5
    6
    7
    (SELECT * FROM `products` LEFT JOIN `brand` ON products.brand_id=brand.id)
    UNION
    (SELECT * FROM `products` RIGHT JOIN `brand` ON products.brand_id=brand.id);

    (SELECT * FROM `products` LEFT JOIN `brand` ON products.brand_id=brand.id WHERE brand.id IS NULL)
    UNION
    (SELECT * FROM `products` RIGHT JOIN `brand` ON products.brand_id=brand.id WHERE products.brand_id IS NULL)

多对多关系

看代码吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#两张基本表
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
);

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);
INSERT INTO `courses` (name, price) VALUES ('物理', 80);

#关系表 我们需要一个关系表来记录两张表中的数据关系
CREATE TABLE IF NOT EXISTS student_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),
FOREIGN KEY (course_id) REFERENCES courses(id)
)

# 学生选课
INSERT INTO `student_select_courses` (student_id,course_id) VALUES (1,1);
INSERT INTO `student_select_courses` (student_id,course_id) VALUES (1,3);

INSERT INTO `student_select_courses` (student_id, course_id) VALUES (3, 2);
INSERT INTO `student_select_courses` (student_id, course_id) VALUES (3, 3);
INSERT INTO `student_select_courses` (student_id, course_id) VALUES (3, 4);

# 查询的需求
# 1. 查询所有有选择的学生选择了哪些课程
SELECT stu.id id,stu.name stuName,stu.age stuAge,cs.id csId,cs.name csName,cs.price csPrice
FROM students AS stu
JOIN `student_select_courses` AS ssc ON stu.id = ssc.student_id
JOIN `courses` AS cs ON ssc.course_id = cs.id;

#2.查询所有学生的选课情况
SELECT stu.id id,stu.name stuName,stu.age stuAge,cs.id csId,cs.name csName,cs.price csPrice
FROM students stu
LEFT JOIN `student_select_courses` ssc ON stu.id=ssc.student_id
LEFT JOIN `courses` cs ON ssc.course_id=cs.id;

#3.查询那些学生没有选课
SELECT stu.id id,stu.name stuName,stu.age stuAge,cs.id csId,cs.name csName,cs.price csPrice
FROM students stu
LEFT JOIN `student_select_courses` ssc ON stu.id=ssc.student_id
LEFT JOIN `courses` cs ON ssc.course_id=cs.id
WHERE cs.id IS NULL;

#4.查询哪些课程没有被选择
SELECT stu.id id,stu.name stuName,stu.age stuAge,cs.id csId,cs.name csName,cs.price csPrice
FROM students stu
RIGHT JOIN `student_select_courses` ssc ON stu.id=ssc.student_id
RIGHT JOIN `courses` cs ON ssc.course_id=cs.id
WHERE stu.id IS NULL;

#5.看一个学生选择了哪些课程
SELECT stu.id id,stu.name stuName,stu.age stuAge,cs.id csId,cs.name csName,cs.price csPrice
FROM students stu
LEFT JOIN `student_select_courses` ssc ON stu.id=ssc.student_id
LEFT JOIN `courses` cs ON ssc.course_id=cs.id
WHERE stu.id = 2;

查询数据 数据类型

核心 转成对象需要 JSON_OBJECT方法 数组 JSON_ARRAYAGG

1
2
3
4
5
6
7
8
9
10
11
12
13
# 将联合查询到的数据转成对象(一对多)
SELECT
products.id pid , products.title title,products.price price,
JSON_OBJECT("id",brand.id,"name",brand.name,"website",brand.website) brand
FROM products LEFT JOIN brand ON products.brand_id =brand.id;

#将查询到的多条数据 组织成对象 放入到一个数组中
SELECT stu.id,stu.name,stu.age,
JSON_ARRAYAGG(JSON_OBJECT('id',cs.id,'name',cs.name,'price',cs.price)) arr
FROM students AS stu
JOIN `student_select_courses` AS ssc ON stu.id = ssc.student_id
JOIN `courses` AS cs ON ssc.course_id = cs.id
GROUP BY stu.id;