MySQL 入门(二)

二、操作数据库

1. 结构化查询语句分类
名称 解释 命令
DDL(数据定义语言) 定义和管理数据对象,如数据库,数据表等 CREATE、DROP、 ALTER
DML(数据操作语言) 用于操作数据库对象中所包含的数据 INSERT、UPDATE、 DELETE
DQL(数据查询语言) 用于查询数据库数据(重点) SELECT
DCL(数据控制语言) 用于管理数据库的语言,包括管理权限及数据更改 GRANT、commit、 rollback
2. 数据库操作

命令行操作数据库(重点)

-- [ ] 可选
-- 创建数据库
CREATE DATABASE [IF NOT EXISTS] 数据库名;
-- 删除数据库
DROP DATABASE [IF EXISTS] 数据库名;
-- 查看数据库
SHOW DATABASES;
-- 使用数据库
USE 数据库名;

工具操作数据库

  • 学习方法:对照 SQLyog 工具,自动生成的语句学习;
  • 固定语法中的单词,需要记忆;
3. 数据值和列类型(了解)
  • 列类型 : 规定数据库中,该列存放的数据类型;
  • 数据类型,对数据库的优化非常重要;
  • 分三类:数值、日期/时间、字符串(字符)类型。

数值类型

  • tinyint:小整数,1个字节
  • smallint:较小整数,2个字节;
  • mediumint:中等整数,3个字节;
  • int(常用):标准整数,4个字节
  • bigint:大整数,8个字节;
  • float:浮点数,4个字节;
  • double:浮点数,8个字节
  • decimal:字符串浮点数,金融计算
image

字符串类型

  • char:字符串固定大小,0~255 字节
  • varchar(常用):可变字符串,0~65535 字节
  • tinytext:微型文本,2^8-1 字节;
  • text:文本串,2^16-1 字节
类型 大小 用途
CHAR 0-255字节 定长字符串
VARCHAR 0-65535 字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65535字节 二进制形式的长文本数据
TEXT 0-65535字节 长文本数据
MEDIUMBLOB 0-16777215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16777215字节 中等长度文本数据
LONGBLOB 0-4294967295字节 二进制形式的极大文本数据
LONGTEXT 0-4294967295字节 极大文本数据

日期/时间类型

  • date:YYYY-MM-DD,日期格式;
  • time:HH:mm:ss,时间格式;
  • datatime(常用):YYYY-MM-DD HH:mm:ss
  • timestamp:时间戳,1970.1.1 ~ 现在 的毫秒数;
  • year:年份。
image

Null 值

  • 理解为 没有值未知值
  • 注意:不要用 NULL 进行算术运算 , 结果仍为NULL。
4. 数据字段属性(重点)
image
  • UnSigned:不允许负数
    • 无符号的;
    • 声明该数据列不允许负数。
  • Zerofill:补 0
    • 用 0 填充;
    • 不足位数的用 0 来填充 , 如 int(3),5 则为 005。
  • 自增:Auto_InCrement
    • 自动增长,每添加一条数据,自动在上一个记录数上加 1(默认);
    • 通常用于设置 主键 , 且为整数类型;
    • 可定义起始值和步长:
      • 当前表设置步长(AUTO_INCREMENT=100):只影响当前表;
      • SET @@auto_increment_increment=5; 影响所有使用自增的表(全局)。
  • 非空:
    • 默认为 NULL,即没有插入该列的数值;
    • 如果设置为 NOT NULL , 则该列 必须有值
  • 默认:
    • 用于设置默认值;
    • 例如:
      • 性别字段,默认为 "男" , 否则为 "女" ;
      • 若无指定,则默认值为 "男"。
5. 创建数据表(DDL 的一种)
  • 手动创建数据表
-- 目标:创建一个school数据库
-- 创建学生表(列,字段)
-- 学号int 登录密码varchar(20) 姓名,性别varchar(2),出生日期(datatime),家庭住址,email
-- 创建表之前 , 一定要先选择数据库
CREATE TABLE IF NOT EXISTS `student`(
    -- MySQL8 INT(M) 改为 INT
    `id` INT NOT NULL AUTO_INCREMENT COMMENT '学号',
    `name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
    `pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
    `sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',
    `brithday` DATETIME DEFAULT NULL COMMENT '生日',
    `address` VARCHAR(100) DEFAULT NULL COMMENT '地址',
    `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
    -- 设置主键
    PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4
  • MySQL8 中更改内容:

    • 需要将 INT(M) 改为 INT,否则告警;
    • 字符集格式:utf8mb4,或在 my.ini 中做相应配置,否则告警;
  • 创建数据表格式:DDL

CREATE TABLE [IF NOT EXISTS] `表名`(
    '字段名1' 列类型 [属性][索引][注释],
    '字段名2' 列类型 [属性][索引][注释],
    #...
    '字段名n' 列类型 [属性][索引][注释]
)[表类型][表字符集][注释];
  • 常用命令(重点)
-- 查看数据库的定义
show create database 数据库名;
-- 查看数据表的定义
show create table 数据表名;
-- 显示表结构
DESC 数据表名;
-- 设置严格检查模式(不能容错了)
SET sql_mode='STRICT_TRANS_TABLES';

注意点:

  • AUTO_INCREMENT 自增;
  • PRIMARY KEY:主键,一般一个表只有一个唯一的主键;
  • 使用英文 (),表的名称和字段,尽量使用 反引号 括起来;
  • 反引号 用于区别 MySQL 保留字与普通字符(键盘 esc 下面的键)
  • 字符串使用单引号括起来;
  • 所有的语句后面加 (英文的),最后一个不用加。

规范

  • 每一个表,都必须存在以下五个字段
    • id:主键
    • version:乐观锁
    • is_delete:伪删除
    • gmt_create:创建时间
    • gmt_update:修改时间
6. 数据表的类型

设置数据表的类型

CREATE TABLE `表名`(
    -- 省略一些代码
    -- Mysql注释
    -- 1. # 单行注释
    -- 2. /*...*/ 多行注释
)ENGINE = MyISAM (or InnoDB)
-- 查看mysql所支持的引擎类型 (表类型)
SHOW ENGINES;
  • MySQL 的数据表的类型:MyISAM、InnoDB、HEAP、BOB、CSV 等;
  • 常用:InnoDB、MyISAM。
名称 MyISAM InnoDB
事务支持 不支持 支持
数据行锁定 不支持 支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间大小 较小 较大,约为 MyISAM 两倍
  • 适用场合(经验) :

    • MyISAM : 节约空间及相应速度;

    • InnoDB : 安全性 , 事务处理及多用户操作数据表。

数据表的存储位置

  • MySQL 数据表以文件方式存放在磁盘中:

    • 包括表文件 , 数据文件 , 以及数据库的选项文件;
    • 位置:Mysql 安装目录\data\下存放数据表 ;
    • 目录名对应数据库名 , 该目录下文件名对应数据表。
  • 注意:(MySQL 8,取消了*.frm

    • InnoDB 类型数据表只有一个 *.frm 文件 , 以及上一级目录的 ibdata1 文件;
    • MyISAM 类型数据表,对应三个文件:
      • *.frm:表结构定义文件;
      • *.MYD:数据文件(data);
      • *.MYI:索引文件(index)。

设置数据表字符集

  • 可为数据库、数据表、数据列设定不同的字符集,设定方法 :

    • 命令:CREATE TABLE 表名()CHARSET = utf8mb4;

    • MySQL 数据库配置文件 my.ini 中的参数设定;

      # 服务端使用的字符集默认为utf8mb4(mysql8)
      character-set-server=utf8mb4
      
    • 建议在创建时设置。

7. 修改数据库

修改表 ( ALTER TABLE )

  • 修改表名:ALTER TABLE 旧表名 RENAME AS 新表名;

    alter table `teacher` rename as `teacher1`;
    
  • 添加字段: ALTER TABLE 表名 ADD 字段名 列属性[属性];

    -- MySQL8 去掉了int位数
    alter table `teacher1` add age int;
    
  • 修改字段:

    • ALTER TABLE 表名 MODIFY 字段名 列类型[属性];
    • ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性[属性];
    -- 修改字段属性
    alter table `teacher1` modify age varchar(10);
    -- 更改字段名,并修改字段属性
    alter table `teacher1` change age age01 int;
    

    区别:

    • change:一般用来重命名字段
    • modify只能修改字段类型和约束,不能重命名字段
  • 删除字段:ALTER TABLE 表名 DROP 字段名;

    alter table `teacher` drop `age`;
    

删除数据表

  • 语法:DROP TABLE [IF EXISTS] 表名;
    • IF EXISTS 为可选, 判断是否存在该数据表;
    • 删除不存在的数据表,会抛出错误。
drop table if exists `teacher`;

其它:

  • 可用反引号(`)为标识符(库名、表名、字段名、索引、别名)包裹,以避免与关键字重名!中文也可以作为标识符;
  • 模式通配符:
    • _ :任意单个字符;
    • %: 任意多个字符,甚至包括零字符;
    • 单引号,需要进行转义 \'
  • SQL 对大小写不敏感 (关键字)。

三、MySQL 数据管理

1. 外键(了解)

外键的概念

  • 外键:如果公共关键字,在一个关系中是主关键字,那么这个公共关键字,被称为另一个关系的外键;
  • 两个关系之间的相关联系;
  • 以另一个关系的外键,作主关键字的表,被称为 主表,具有此外键的表被称为 主表的从表
  • 在实际操作中:
  • 将一个表的值,放入第二个表来表示关联,所使用的值,是第一个表的主键值(在必要时可包括复合主键值);
  • 第二个表中,保存这些值的属性,称为外键(foreign key)。
  • 外键作用:保持数据一致性、完整性,控制存储在外键表中的数据(约束),使两张表形成关联,外键只能引用外表中的列的值,或使用空值。

创建外键

  • 方式一:创建子表同时创建外键;
-- 年级表 (id 年级名称)
CREATE TABLE `grade` (
  `gradeid` INT NOT NULL AUTO_INCREMENT COMMENT '年级ID',
  `gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
  PRIMARY KEY (`gradeid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4

-- 学生信息表 (学号,姓名,性别,年级,手机,地址,出生日期,邮箱,身份证号)
CREATE TABLE `student` (
  `studentno` INT NOT NULL COMMENT '学号',
  `studentname` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
  `sex` TINYINT DEFAULT '1' COMMENT '性别',
  `gradeid` INT DEFAULT NULL COMMENT '年级',
  `phoneNum` VARCHAR(50) NOT NULL COMMENT '手机',
  `address` VARCHAR(255) DEFAULT NULL COMMENT '地址',
  `birthday` DATETIME DEFAULT NULL COMMENT '生日',
  `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
  `idCard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
  PRIMARY KEY (`studentno`),
  -- 设置外键
  KEY `FK_gradeid` (`gradeid`),
  -- 外键添加约束(执行引用)references 引用
  CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4
  • 方式二:创建子表完毕后,修改子表添加外键;
-- alter table 表名 add constraint 约束名 foreign key(作为外键的列) references 主表(字段)

alter table `student`
add constraint `FK_gradeid` foreign key(`gradeid`) references `grade`(`gradeid`);

删除外键

  • 操作:删除 grade 表,报错
image
  • 注意:删除具有主外键关系的表时,要先删从表,后删主表;
-- 删除外键
ALTER TABLE student DROP FOREIGN KEY FK_gradeid;
-- 发现执行完上面的,索引还在,所以还要删除索引
-- 注:这个索引是建立外键的时候默认生成的
ALTER TABLE student DROP INDEX FK_gradeid;
  • 以上操作,都是物理外键,数据库级别的外键,不建议使用!!
  • 数据库为单纯的表,只用来存储数据,只有行(数据)和列(字段);
  • 多张表同时操作,使用外键时,用程序实现
2. DML 语言(重点):数据操作语言
  • 数据库意义:数据存储、数据管理;
  • 管理数据库数据方法:
    • 通过 SQLyog 等管理工具,管理数据库数据;
    • 通过 DML 语句,管理数据库数据。
  • 操作数据库对象,所包含的数据:
    • INSERT:添加数据;
    • UPDATE:更新数据;
    • DELETE:删除数据。
3. 添加数据

INSERT 命令

  • 语法:
INSERT INTO 表名[(字段1,字段2,字段3,...)] VALUES('值1','值2','值3')
  • 注意:
    • 字段或值之间,用英文 , 隔开 ;
    • 字段1,字段2.. 该部分可省略,但添加的值,务必与表结构,数据列,顺序相对应,且数量一致;
    • 可同时插入多条数据,values 后用英文 , 隔开。
-- INSERT INTO 表名[(字段1,字段2,字段3,...)] VALUES('值1','值2','值3')
INSERT INTO `grade`(`gradename`) VALUES ('大一');
-- 一次插入多条数据
INSERT INTO `grade`(`gradename`) VALUES ('大二'),('大三');
  • 主键自增,测试省略字段,进行插入操作:
-- 报错,与表结构不对应
INSERT INTO `grade` VALUES ('大四');
-- 操作成功,与表结构对应
INSERT INTO `grade` VALUES ('4','大四');
image
  • 结论:字段1,字段2... 该部分可省略,前提是,添加的值,务必与表结构,数据列,顺序相对应,且数量一 致。
4. 修改数据

update 命令

  • 语法:
UPDATE 表名 SET column_name=value [,column_name2=value2,...] [WHERE condition];
  • 注意:
    • column_name:要更改的数据列;
    • value:修改后的数据,可以为变量,具体指,表达式或者嵌套的 SELECT 结果;
    • condition:为筛选条件,如不指定,则修改该表的所有列数据。

where 条件子句

  • 简单理解为:有条件的,从表中筛选数据;
运算符 含义 范围 结果
= 等于 5=6 false
<> 或 != 不等于 5!=6 true
> 大于 5>6 false
< 小于 5<6 true
>= 大于等于 5>=6 false
<= 小于等于 5<=6 true
BETWEEN 在某个范围之间 BETWEEN 5 AND 10
AND 并且 5 > 1 AND 1 > 2(&&) false
OR 5 > 1 OR 1 > 2(||) true
  • 测试:
-- 修改年级信息
UPDATE `grade` SET `gradename` = '高中' WHERE `gradeid` = 1;
-- value值可以是一个变量 CURRENT_TIME:时间变量
UPDATE `student` SET `birthday`=CURRENT_TIME WHERE `name`='测试' AND `sex`='0';
5. 删除数据

DELETE 命令

  • 语法:
DELETE FROM `表名` [WHERE condition];
  • 注意:condition 为筛选条件,如不指定,则删除该表的所有列数据;
-- 删除最后一个数据
DELETE FROM `grade` WHERE `gradeid`=5;

TRUNCATE 命令

  • 作用:清空表数据,表结构、索引、约束等不变 ;

  • 语法:

TRUNCATE [TABLE] `数据表名`;
-- 清空年级表
truncate `grade`;
  • 测试:
-- 创建一个测试表
CREATE TABLE `test` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `coll` VARCHAR(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4

-- 插入测试数据
INSERT INTO `test`(`coll`) VALUE('row1'),('row2'),('row3');
-- 方式1:清空表数据 (delete不带where条件)
DELETE FROM `test`;
-- 方式2:清空表数据 (truncate)
TRUNCATE TABLE `test`;
  • 注意:
    • 区别于 DELETE 命令;
    • 相同:都能删除数据,不删除表结构,但 TRUNCATE 速度更快;
    • 不同:
      • TRUNCATE 重新设置 索引 计数器,不会记录日志;
      • TRUNCATE 不会对事务有影响。
  • delete 问题:重启数据库后(了解)
    • InnoDB:自增列会从1开始(存在内存中的,断电即失);
    • MyISAM:继续从上一个自增量开始(存在文件中,不丢失)。

四、使用 DQL 查询数据(重点)

1. DQL 语言
  • DQL(Data Query Language 数据查询语言):
    • 查询数据库数据,如 SELECT 语句;
    • 单表查询、多表的复杂查询、嵌套查询;
    • 数据库语言中最核心、最重要的语句;
    • 使用频率高。

SELECT 语法

SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
    [left | right | inner join table_name2] -- 联合查询
    [WHERE ...] -- 指定结果需满足的条件
    [GROUP BY ...] -- 指定结果按照哪几个字段来分组
    [HAVING] -- 过滤分组的记录必须满足的次要条件
    [ORDER BY ...] -- 指定查询记录按一个或多个条件排序
    [LIMIT {[offset,]row_count | row_countOFFSET offset}];
    -- 指定查询的记录从哪条至哪条
  • 注意:[ ] 可选,{ } 必选,可选参数必须按语法的前后顺序,否则报错。
  • 导入 SQL 文件:
-- 创建一个school数据库
DROP DATABASE IF EXISTS `school`;
CREATE DATABASE IF NOT EXISTS `school`;
USE `school`;

-- 创建年级表
DROP TABLE IF EXISTS `grade`;
CREATE TABLE IF NOT EXISTS `grade` (
  `GradeID` INT NOT NULL AUTO_INCREMENT COMMENT '年级编号',
  `GradeName` VARCHAR(50) NOT NULL COMMENT '年级名称',
  PRIMARY KEY (`GradeID`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
-- 插入年级数据
INSERT INTO `grade` (`GradeID`,`GradeName`) 
VALUES
(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');

-- 创建成绩表
DROP TABLE IF EXISTS `result`;
CREATE TABLE IF NOT EXISTS `result` (
  `StudentNo` INT NOT NULL COMMENT '学号',
  `SubjectNo` INT NOT NULL COMMENT '课程编号',
  `ExamDate` DATETIME NOT NULL COMMENT '考试日期',
  `StudentResult` INT NOT NULL COMMENT '考试成绩',
  KEY `SubjectNo` (`SubjectNo`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;
-- 插入成绩数据
INSERT INTO `result`(`StudentNo`,`SubjectNo`,`ExamDate`,`StudentResult`)
VALUES
(1000,1,'2013-11-11 16:00:00',85),
(1000,2,'2013-11-12 16:00:00',70),
(1000,3,'2013-11-11 09:00:00',68),
(1000,4,'2013-11-13 16:00:00',98),
(1000,5,'2013-11-14 16:00:00',58),
(1001,1,'2013-11-11 16:00:00',80),
(1001,2,'2013-11-12 16:00:00',90),
(1001,3,'2013-11-11 09:00:00',78),
(1001,4,'2013-11-13 16:00:00',90),
(1001,5,'2013-11-14 16:00:00',68),
(1002,1,'2013-11-11 16:00:00',88),
(1002,2,'2013-11-12 16:00:00',79),
(1002,3,'2013-11-11 09:00:00',52),
(1002,4,'2013-11-13 16:00:00',69),
(1002,5,'2013-11-14 16:00:00',77),
(1003,1,'2013-11-11 16:00:00',90),
(1003,2,'2013-11-12 16:00:00',89),
(1003,3,'2013-11-11 09:00:00',96),
(1003,4,'2013-11-13 16:00:00',83),
(1003,5,'2013-11-14 16:00:00',79);

-- 创建学生表
DROP TABLE IF EXISTS `student`;
CREATE TABLE IF NOT EXISTS `student` (
  `StudentNo` INT NOT NULL COMMENT '学号',
  `LoginPwd` VARCHAR(20) DEFAULT NULL,
  `StudentName` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
  `Sex` TINYINT DEFAULT NULL COMMENT '性别,0或1',
  `GradeId` INT DEFAULT NULL COMMENT '年级编号',
  `Phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空',
  `Address` VARCHAR(255) NOT NULL COMMENT '地址,允许为空',
  `BornDate` DATETIME DEFAULT NULL COMMENT '出生时间',
  `Email` VARCHAR(50) NOT NULL COMMENT '邮箱账号允许为空邮箱账号允许为空',
  `IdentityCard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
  PRIMARY KEY (`StudentNo`),
  UNIQUE KEY `IdentityCard` (`IdentityCard`),
  KEY `Email` (`Email`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;
-- 插入学生数据
INSERT INTO `student`(`StudentNo`,`LoginPwd`,`StudentName`,`Sex`,`GradeId`,`Phone`,`Address`,`BornDate`,`Email`,`IdentityCard`)
VALUES
(1000,'123456','张伟',0,2,'13800001234','北京朝阳','1980-1-1','text123@qq.com','123456198001011234'),
(1001,'123456','赵强',1,3,'13800002222','广东深圳','1990-1-1','text111@qq.com','123456199001011233'),
(1002,'123456','张三',0,2,'13800001207','北京海淀','1983-2-15','text207@qq.com','123456198301011234'),
(1003,'123456','李四',0,2,'13800003333','北京通州','1985-10-18','text333@qq.com','123456198501011234'); 

-- 创建科目表
DROP TABLE IF EXISTS `subject`;
CREATE TABLE IF NOT EXISTS `subject` (
  `SubjectNo` INT NOT NULL AUTO_INCREMENT COMMENT '课程编号',
  `SubjectName` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
  `ClassHour` INT DEFAULT NULL COMMENT '学时',
  `GradeId` INT DEFAULT NULL COMMENT '年级编号',
  PRIMARY KEY (`SubjectNo`)
) ENGINE=INNODB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4;
-- 插入科目数据
INSERT INTO `subject`(`SubjectNo`,`SubjectName`,`ClassHour`,`GradeId`) 
VALUES
(1,'高等数学-1',110,1),
(2,'高等数学-2',110,2),
(3,'高等数学-3',100,3),
(4,'高等数学-4',130,4),
(5,'C语言-1',110,1),
(6,'C语言-2',110,2),
(7,'C语言-3',100,3),
(8,'C语言-4',130,4),
(9,'Java程序设计-1',110,1),
(10,'Java程序设计-2',110,2),
(11,'Java程序设计-3',100,3),
(12,'Java程序设计-4',130,4),
(13,'数据库结构-1',110,1),
(14,'数据库结构-2',110,2),
(15,'数据库结构-3',100,3),
(16,'数据库结构-4',130,4),
(17,'C#基础',130,1);
2. 指定查询字段
-- 查询表中所有的数据列结果,采用 *,效率低,不推荐
-- 查询所有学生信息
SELECT * FROM `student`;
-- 查询指定列(字段:学号 , 姓名)
SELECT `StudentNo`,`StudentName` FROM `student`;

AS 子句作为别名(AS 关键词可以省略)

  • 作用:

    • 可给数据列,取一个新别名;
    • 可给表,取一个新别;
    • 可把经计算,或总结的结果,用另一个新名称来代替。
  • 注意:别名可以不加引号,可以是中文

-- 为列取别名(AS可以省略)
SELECT `StudentNo` AS 学号,`StudentName` AS 姓名 FROM `student`;
-- 为表取别名
SELECT `StudentNo` 学号,`StudentName` 姓名 FROM`student` s;
-- 为查询结果设置别名
-- CONCAT(a,b)函数,拼接字符串
SELECT CONCAT('姓名:',`StudentName`) AS 新姓名 FROM `student`;
image

distinct 关键字(去重复)

  • 作用 : 去掉 SELECT 查询返回结果中,重复的记录 ( 列值相同 ) , 只返回一条;
-- 查看考试成绩(所有)
SELECT * FROM `result`; 
-- 查看参加考试人员(按学号),有重复
SELECT `StudentNo` FROM `result`;
-- distinct 去除重复项(默认是ALL)
SELECT DISTINCT `StudentNo` 学号去重 FROM `result`;
image

数据库的列(使用表达式)

  • 语法:select 表达式 from 表名;
  • 数据库中的表达式:文本值、列值、NULL、函数、操作符等组成;
  • 应用场景:
    • SELECT 返回结果列中使用;
    • SELECT 的 ORDER BY , HAVING 等子句中使用;
    • DML 语句中的 where 条件语句中使用。
-- selcet查询中使用表达式
-- 查询自增步长(变量)
SELECT @@auto_increment_increment;
-- 查询版本号(函数)
SELECT VERSION();
-- 计算结果(表达式)
SELECT 100*2+10 AS 计算结果;
-- 查看学生成绩,并将成绩整体 +1
SELECT `StudentNo` 学号,`StudentResult`+1 提分后 FROM `result`;
3. where 条件语句
  • 作用:检索数据表中,符合条件的记录;
  • 搜索条件:一个或多个逻辑表达式,结果一般为 truefalse

逻辑操作符 MySQL8 运算符

运算符 语法 描述
ADN 或 && a AND b 或 a && b 逻辑与:两个都为真,结果才为真
OR 或 || a OR b 或 a || b 逻辑或:一个为真,结果为真
NOT ! not a 或 !a 逻辑非:取反
  • 运算符尽量使用英文字母
  • 满足条件的查询(where):
-- 查询成绩85-100之间的数据
SELECT `StudentNo` 学号,`StudentResult` 成绩 FROM `result`
WHERE `StudentResult`>=85 AND `StudentResult`<=100;
-- AND也可以写成 &&
SELECT `StudentNo`,`StudentResult` FROM `result`
WHERE `StudentResult`>=85 && `StudentResult`<=100
-- 模糊查询 between(对应:精确查询)
SELECT `StudentNo`,`StudentResult` FROM `result`
WHERE `StudentResult` BETWEEN 85 AND 100;
-- 查看,除学号为1000的,其它学生成绩(!= 或 <>)
SELECT `StudentNo`,`StudentResult` FROM `result`
WHERE `StudentNo`!=1000;
-- 使用not
SELECT `StudentNo`,`StudentResult` FROM `result`
WHERE NOT `StudentNo`=1000;

模糊查询:比较操作符

操作符 语法 描述
IS NULL a IS NULL 操作符为 NULL,结果为真
IS NOT NULL a IS NOT NULL 操作符不为 NULL,结果为真
BETWEEN a BETWEEN b AND c a 范围在 b 与 c 之间,结果为真
LIKE a LIKE b SQL 模式匹配:a匹配b,结果为真
IN a IN (a1,a2,a3,...) a 等于 a1,a2...中的一个,结果为真
  • 注意:
    • 数值数据类型的记录之间,才能进行算术运算;
    • 相同数据类型的数据之间,才能进行比较;
    • IN 括号中,是具体的一个或多个值,不能用通配符。
  • 模糊查询:between、and、like、in、null
    • 通配符:
      • %:0 到任意多个字符;
      • _ :任意单个字符;
      • 特殊字符,需要进行转义 \
-- 多字符匹配:like 结合 %
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `StudentName` LIKE '张%';
-- 单字符匹配:like 结合 _
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `StudentName` LIKE '张_';
-- 查询姓张的同学,后面只有两个字的:LIKE '张__'
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `StudentName` LIKE '张__'
-- 查询名字中含有 嘉 字的
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `StudentName` LIKE '%嘉%';

-- 查询姓名中含有特殊字符的需要使用转义符号 '\'
-- 自定义转义符关键字: ESCAPE ':'
-- =============================================
-- IN(具体的一个或多个值,不能用通配符)
-- =============================================
-- 查询学号为1000,1001,1002的学生姓名
SELECT `StudentNo`,`StudentName` FROM`student`
WHERE `StudentNo` IN('1000','1001','1002');
-- 查询地址在北京朝阳,广东深圳的学生
SELECT `StudentNo`,`StudentName` FROM `student`
WHERE `Address` IN('北京朝阳','广东深圳');

-- NULL 空
-- =============================================
-- 查询email没有填写的学生信息
-- 不能直接写=NULL(错误),用 is null
SELECT `StudentName` FROM `student`
WHERE `Email`='' OR `Email` IS NULL;
-- 查询出生日期填写的学生信息(不为空)
SELECT `StudentName`,`BornDate` FROM `student`
WHERE `BornDate` IS NOT NULL
4. 联表查询

JOIN 对比

操作符 描述
inner join 如果表中,至少有一个匹配,则返回行
left join 右表 中没有匹配,也从 左表 中返回所有行
right jion 左表 中没有匹配,也从 右表 中返回所有行
image
image

连接查询:

  • 多张数据表数据查询,可通过连接运算符 JOIN 实现;
  • inner join(内连接):查询两个表中结果的交集;
  • 外接接(outer join):
    • left join(左外连接):以左表为基准,右表进行匹配,匹配不上的,返回左表的记录,右表以 NULL 填充;
    • right join(右外连接):以右表为基准,左表进行匹配,匹配不上的,返回右表的记录,左表以 NULL 填充;
  • 等值连接和非等值连接;
  • 自连接。
  • 测试:
    • 连接查询:join 连接的表 on 判断条件
    • 等值查询:join 连接的表 where 判断条件
-- 查询参加考试的学生信息(学号、学生姓名、科目编号、分数)
-- 所有学生信息
SELECT * FROM student;
-- 所有成绩信息
SELECT * FROM result;

/*
思路:
1:分析需求,确定查询的列来源于两个类 student、result,连接查询
2:确定使用哪种连接查询?(内连接)
确定交叉点:不同表中,共有的列信息(如:学号)
判断条件:学生表中的 StudentNo= 成绩表中的 StudentNo
*/

-- 等值连接
SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult`
FROM `student` s,`result` r
WHERE s.`StudentNo`=r.`StudentNo`;

-- 内连接(inner join)
SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult`
FROM `student` s INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`;

-- 在student插入一条学生记录(无考试成绩)
-- 左连接(left join):查询结果中,包含新插入无成绩学生信息
SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult`
FROM `student` s LEFT JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`;

-- 右连接(right join):只包含有成绩学生信息
SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult`
FROM `student` s RIGHT JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`;

-- 查询缺考学生(左连接)
SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult`
FROM `student` s LEFT JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
WHERE `StudentResult` IS NULL;

-- 查询参加考试的同学信息(4张表:学号、年级名称、学生姓名、科目名、分数)
SELECT s.`StudentNo`,`GradeName`,`StudentName`,`SubjectName`,`StudentResult`
FROM `student` s INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
INNER JOIN `grade` g
ON s.`GradeId`=g.`GradeID`;

-- 查询 高等数学-4 的所有考试结果(学号、学生姓名、科目名称、成绩)
SELECT s.`StudentNo` 学号,`StudentName` 学生姓名,`SubjectName` 科目名称,`StudentResult` 成绩
FROM `student` s INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE `SubjectName`='高等数学-4';

分析:

  • 要查询哪些数据:select ...;
  • 从哪几个表中查:from 表名 xxx join 连接的表 on 交叉条件;
  • 多张表查询:先查两张,再逐个表增加。

自连接(了解)

  • 自连接:
    • 数据表与自身进行连接;
    • 核心:一张表,拆为两张一样的表即可
  • SQL 文件:
-- 创建表
CREATE TABLE `category` (
  `categoryid` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主题id',
  `pid` int NOT NULL COMMENT '父id',
  `categoryName` varchar(50) NOT NULL COMMENT '主题名字',
  PRIMARY KEY (`categoryid`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4;

-- 插入记录
INSERT INTO `category`(`categoryid`,`pid`,`categoryName`)
VALUES('2','1','信息技术'),
('3','1','软件开发'),
('4','3','数据库'),
('5','1','美术设计'),
('6','3','web开发'),
('7','5','ps技术'),
('8','2','办公信息');
image
  • 表折分:

    • 父类

      categoryid categoryName
      2 信息技术
      3 软件开发
      5 美术设计
    • 子类

      pid categoryid categoryName
      3 4 数据库
      2 8 办公信息
      3 6 web开发
      5 7 ps技术
    • 操作:查询父类对应子类的关系

      父类 子类
      信息技术 办公信息
      软件开发 数据库
      软件开发 web开发
      美术设计 ps技术
  • 自连接测试:

/*
将栏目的父子关系呈现出来 (父栏目名称,子栏目名称)
核心思想:把一张表看成两张一模一样的表,然后将这两张表连接查询
*/
-- 内连接方式:
SELECT a.`categoryName` AS 父栏目,b.`categoryName` AS 子栏目
FROM `category` AS a INNER JOIN `category` AS b
ON a.`categoryid`=b.`pid`;

-- 等值查询:
SELECT a.`categoryName` AS 父栏目,b.`categoryName` AS 子栏目
FROM `category` AS a,`category` AS b
WHERE a.`categoryid`=b.`pid`;
5. 排序和分页

排序

  • 根据指定的列(字段),对结果集进行排序;

  • 语法 : ORDER BY ...

    • ASC:升序(默认);
    • DESC:降序。
  • 测试:

-- 查询 高等数学-4 的所有考试结果(学号、学生姓名、科目名称、成绩)
-- 按成绩降序排序
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM `student` s INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE `SubjectName`='高等数学-4'
ORDER BY `StudentResult` DESC;

分页

  • 语法 : SELECT * FROM 表名 LIMIT [offset,] rows | rows OFFSET offset;

  • 作用:

    • 缓解数据库压力;
    • 提高网络传输速度;
    • 更好的用户体验。
  • 推导:

    • 第一页 : limit 0,5(记录起始值,记录条数);
    • 第二页 : limit 5,5;
    • 第三页 : limit 10,5;
  • 公式:limit (n-1)*pageSzie,pageSzie;

    • pageSzie:每页显示数据条数;
    • (n-1)*pageSize:起始值;
    • n:当前页;
    • 总页数:数据总数/页面显示条数。
  • 测试:

-- 每页显示3条数据
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM `student` s INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE `SubjectName`='高等数学-4'
ORDER BY `StudentResult` DESC
LIMIT 0,3

-- 查询 高等数学-1 课程成绩前2名并且分数大于80的学生信息(学号、姓名、课程名、分数)
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM `student` s INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE `SubjectName`='高等数学-1' AND `StudentResult`>80
ORDER BY `StudentResult` DESC
LIMIT 0,2
6. 子查询
  • 在查询语句 WHERE 条件语句中,嵌套另一个查询语句;

    select * from user where id = (select id from grade);
    
  • 嵌套查询,可由多个子查询组成(由里及外);

  • 子查询返回的结果,一般都是集合,建议使用 IN 关键字;

  • 测试:

-- 查询 高等数学-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列
-- 方式1:连接查询
SELECT `StudentNo`,r.`SubjectNo`,`StudentResult`
FROM `result` r INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE `SubjectName`='高等数学-1'
ORDER BY `StudentResult` DESC;

-- 方式2:使用子查询(由里及外)
SELECT `StudentNo`,`SubjectNo`,`StudentResult`
FROM `result`
WHERE `SubjectNo`=(
SELECT `SubjectNo` FROM `subject`
WHERE `SubjectName`='高等数学-1'
)
ORDER BY `StudentResult` DESC;

-- 查询课程为 高等数学-1 且分数不小于80分的学生的学号和姓名
-- 方式1:连接查询
SELECT s.`StudentNo`,`StudentName` FROM `student` s
INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE `SubjectName`='高等数学-1' AND `StudentResult`>=80

-- 方法2:使用连接查询+子查询
SELECT s.`StudentNo`,`StudentName` FROM `student` s
INNER JOIN `result` r
ON s.`StudentNo`=r.`StudentNo`
WHERE `SubjectNo`=(
    SELECT `SubjectNo` FROM `subject`
    WHERE `SubjectName`='高等数学-1' AND `StudentResult`>=80
);

-- 方法3:使用子查询
-- 分步写简单sql语句,然后将其嵌套起来
SELECT `StudentNo`,`StudentName` FROM `student` 
WHERE `StudentNo` IN(
    SELECT `StudentNo` FROM `result`
    WHERE `StudentResult`>=80 AND `SubjectNo`=(
        SELECT `SubjectNo` FROM `subject`
        WHERE `SubjectName`='高等数学-1'
    )
);
7. 分组和过滤
  • 分组:GROUP BY...
  • 过滤:HAVING...
-- 查询不同课程的平均分,最高分,最低分
-- 前提:根据不同的课程进行分组
SELECT `SubjectName`,AVG(`StudentResult`) AS 平均分,
MAX(`StudentResult`) AS 最高分,
MIN(`StudentResult`) AS 最低分
FROM `result` r 
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
-- 分组:按课程编号
GROUP BY r.`SubjectNo`
-- 过滤:可使用别名
HAVING 平均分>80
  • 注意:
    • where 写在 group by(分组)前面;
    • 分组后面的筛选,要使用 HAVING...;
    • HAVING 是从前面筛选的字段再筛选,where 是从数据表的字段,直接进行筛选。
8. select 小结
  • 顺序非常重要:
select 去重 要查询的字段 from 表名(注意:表和字段可以取别名 as)
xxx join 要连接的表 on 等值判断
where(具体的值,子查询语句)
group by(用哪个字段来分组)
having(过滤分组后的信息,条件与where一样,位置不同)
order by(排序 升序,降序)
limit 分页起始值,记录条数;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容