看完上一个章节,相信你已经掌握了JSPJSTLSERVLET相关技术的基础知识和用法,已经初步具备了制作动态网页的实力,今天我们来开启一门新的知识——数据库。
之前我们有提到网页提供的数据是动态的,我们的数据大多数是从数据库中存取的。数据库就是我们存取数据的一种工具,可以暂时理解为我们存取数据的一个仓库。一般来讲,在互联网行业MYSQL是最流行的数据库,没有之一。
结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。
SQL有以下特点:
1)SQL是一种关系型数据库的查询语言,所有的关系型数据库都支持,SQL可以在不同的数据库中使用。
2) 由于数据库厂商不同,不同的数据库厂商的数据库有本地方言,SQL在不同的数据库中的写法有一些差别。
SQL语句通常可以分为以下几类:
1)DDL(Data Definition Language数据定义语言) 比如建库,建表 (CREATE DATABSET CREAT TABLE)等等。
2)DML(Data Manipulation Language DML 数据操纵语言),比如对表中的记录进行增删改等操作(INSERT UPDATE DELETE)。
3)DQL(Data Query Language数据查询语言),比如对表中的查询操作(SELECT) 。
4)DCL(DCL Data Control Language数据控制语言),比如对用户的数据访问权限进行授权(GRANT INVOKE)。
作为一只开发猿,攻城狮,使用得最多的是DQL和DML,DDL和DCL的执行权限往往在DBA(数据库管理员)手中。
我们来看看怎么创建数据库:
CREATE DATABASE 数据库名 DEFAULT CHARACTER SET字符集名; (注意空格,字符集名 建议使用'utf8')
例子:
CREATE DATABASE test01 DEFAULT CHARACTER SET 'utf8'; (注意字符集名的单引号,utf8能比较好的支持中文)
创建数据库前可以判断下数据库是否存在
CREATE DATABASE IF NOT EXISTS test01 DEFAULT CHARACTER SET 'utf8';
想知道怎么查看数据库创建时的信息吗?
SHOW CREATE DATABASE 数据库名;(可以查询数据库创建时的信息)
例子:
SHOW CREATE DATABASE test01;
你还可以对数据库进行修改
ALERT DATABASE 数据库名 要修改的内容;
比如修改字符集
ALERT DATABASE test01 DEFAULT CHARACTER SET 'gbk'; (将数据库字符集转换为gbk)
注意:修改字符集这种事情,在实际工作中的线上程序中几乎不可能发生,字符集这种事情,大家应该先确定好,直接修改数据风险极大,大家了解即可。
如何使用一个数据库?使用数据库,代表当前要对哪个数据库做操作。
USE DATABASE 数据库名;
例子:
USE DATABASE test01;
查看当前正在使用的数据库:
SELECT DATABSE();
怎样删除一个数据库?
DROP DATABASE 数据库名;
例子:
DROP DATABASE test01;
注意:删除数据库作为语法掌握即可,数据库删除后,数据就没有了,大家了解即可!
相信大家都见过表格吧?有表头,有行数据。比如下面这个东西:姓名、年龄、性别、备注就是列名,通过这种方式,我们能直观的知道张三,胖虎,如花的信息,胖虎 19 男 胖胖哒,就是行数据,一行数据代表了一个人的信息。
姓名 | 年龄 | 性别 | 备注 |
---|---|---|---|
二丫 | 19 | 女 | 漂亮 |
胖虎 | 20 | 男 | 胖胖哒 |
如花 | 21 | 女 | 难看 |
我们通常使用数据库的表(TABLE)来存放数据,TABALE也是有行列的,和表格类似,只是我们常常将表头叫做字段名。
我们怎样才能使用数据库建立数据表呢?在这之前,你得先了解数据库的数据类型。
比如1,2,3,这样的数字,我们通常称为整数,3.1415926这样的数字我们通常称为小数,2019-10-01 10:00:00这样的数据我们通常称为时间。我们在数据库中存放数据,也需要对数据进行分类。数据类型就是对数据的一个分类。下表是MYSQL数据库中的数据类型(不用刻意去记忆,用得多了就熟悉了)。
数据类型 | 存储空间 | 数据范围(含负数) | 数据范围(不含负数) | 用途 |
---|---|---|---|---|
TINYINT | 1 字节 | (-128,127) | (0,255) | 小整数值,一般用于存储状态啊,性别一类的数据,就几个值不用太变化,比如1表示男2表示女 |
SMALLINT | 2 字节 | (-32 768,32 767) | (0,65 535) | 大整数值,不常用 |
MEDIUMINT | 3 字节 | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 字节 | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值,视数据情况而定,需要考虑数据大小是否够用 |
BIGINT | 8 字节 | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值,如果用作主键对于整型数据,推荐使用BIGINT,INT太小不够用 |
FLOAT | 4 字节 | (-3.402 823 466 E 38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E 38) | 0,(1.175 494 351 E-38,3.402 823 466 E 38) | 单精度 |
DOUBLE | 8 字节 | (-1.797 693 134 862 315 7 E 308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E 308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E 308) | 双精度 |
DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M 2否则为D 2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值,推荐使用,数据较大,小数位可掌控 |
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 没有时分秒 |
DATETIME | 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 精确到秒 |
TIMESTAMP | 4 | 结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 精确到毫秒 对时间有要求时推荐使用 |
CHAR | 0-255字节 | 定长字符串 | ||
VARCHAR | 0-65535 字节 | 变长字符串,常用,存储空间较为灵活 | ||
TINYBLOB | 0-255字节 | 不超过 255 个字符的二进制字符串 | ||
TINYTEXT | 0-255字节 | 短文本字符串 | ||
BLOB | 0-65 535字节 | 二进制形式的长文本数据 | ||
TEXT | 0-65 535字节 | 长文本数据 | ||
MEDIUMBLOB | 0-16 777 215字节 | 二进制形式的中等长度文本数据 | ||
MEDIUMTEXT | 0-16 777 215字节 | 中等长度文本数据 | ||
LONGBLOB | 0-4 294 967 295字节 | 二进制形式的极大文本数据 | ||
LONGTEXT | 0-4 294 967 295字节 | 极大文本数据 |
注意:[]的部分为可选部分,在创建表的时候可以不写,NOT NULL的含义是,是否允许为空,如果一个字段被设置为NOT NULL那么,这个字段必须有值。
PRIMARY KEY的意思是主键,所谓主键,就是指一张表里,一行记录的唯一标识,在一张表里主键是不允许重复的。
接下来打开你的SQLyog,我们来建立一张表,我们用一行数据来表示学生的基本信息:
编号,姓名,性别,年龄,入学时间备注:
CREATE TABLE `test01`.`student`(
`ID` BIGINT(21) NOT NULL AUTO_INCREMENT COMMENT '编号,主键',
`name` VARCHAR(50) COMMENT '姓名',
`sex` TINYINT(4) COMMENT '性别(1男2女)',
`age` TINYINT(4) COMMENT '年龄',
`admission_date` TIMESTAMP COMMENT '入学时间',
`remark` VARCHAR(200) COMMENT '备注',
PRIMARY KEY (`ID`)
) ENGINE=INNODB CHARSET=utf8;
注意:
COMMENT 后面是字段的备注,往往代表字段的说明,说明字段的真实含义,建议在建表的时候加上便于维护。
PRIMARY KEY (`ID`) 指定了ID作为主键
AUTO_INCREMENT代表自增,每次写入数据时,不写该字段,该字段默认加1.
ENGINE=INNODB CHARSET=utf8; 指定表的存储引擎为INNODB 字符集为utf8. (存储引擎:数据库存储数据的方式,暂时不提)
语句准备好了,直接执行就好。
如何查询建表语句?
SHOW CREATE TABLE 表名;
查看表结构:DESC 表名;
注意:在实际工作中,字段类型确定了轻易不会从一种类型转换到另一种类型,倒是可能扩展字段长度,大家在设计表的时候要考虑充分。真正的生产系统是轻易不会drop字段的,了解语法就好。
插入数据:
INSERT INTO 表名 (字段名1, 字段名2, 字段名3…) VALUES (值1, 值2, 值3);
值1,值2,值3分别对应字段名1 字段名2 字段名3的数据。
例子:
INSERT INTO student (name,sex,age,admission_date,remark) VALUES('张三',1,18,'2019-09-01','高个子');
再来一条:
INSERT INTO student (name,sex,age,admission_date,remark) VALUES('李四',1,18,NOW(),'矮个子');
NOW()时一个数据库函数,代表当前的时间,如果要取当前时间可以用NOW()函数。
注意:字符类型的数据再需要单引号。
ID时自增的主键,所以不用在插入的时候写入数值,数据库会自动给它加一,书写字段名或值时多个字段或值用英文半角逗号分隔,最后一个字段名后是没有逗号的。
修改数据
UPDATE TABLE 表名 SET 字段1=新的值,字段2=新的值… [where 限定条件]
例子:
UPDATE student SET NAME='王五' ,sex=2,age=19 ,admission_date=NOW(),remark='妹子' WHERE ID=1;
注意:
UPDATE 语句使用时往往要加上限定语句 where 字段名=值,如果不加,修改的是全表数据,当然,如果你需要修改全部数据,不加也行。
删除数据
DELETE FROM TABLE 表名 [where 限定条件]
例子:
DELETE FROM student WHERE ID=1;
注意:
DELETE语句使用时往往要加上限定语句 where 字段名=值,如果不加,修改的是全表数据,当然,如果你需要修改全部数据,不加也行。
清空表:
TUNCATE TABLE 表名
注意:相当于drop一张表并创建一张新表,快速的清空一张表的记录,实际使用很少,一旦误操作,数据会丢失而且慎用。大家了解语法和作用就好。
查询一张表所有记录:
SELECT * FROM 表名;比如:
SELECT * FROM student;
查询部分字段:
SELECT 字段名1,字段名2,字段名3,…FROM 表名;
例子:
SELECT name,sex,age,admission_date,remark FROM student
改变显示的列名:
SELECT 字段名1 as 新名字,字段名2 as 新名字,字段名3 as 新名字,…FROM 表名;
SELECT name as xingming,sex as xingbie,age as nianling,admission_date as ruxueshijian,remark as beizhu FROM student
统计表里的记录条数:
SELECT COUNT(*) FROM student
count 时mysql 提供的函数,用于统计满足条件的记录数量。
看过了上面的查询语句,你已经有了简单的认知,接下来我们看看查询语句的写法:
SELECT [DISTINCT] 字段1 [AS 别名], ..., 字段N [AS 别名] FROM [库名.]表名
[
WHERE 约束条件
GROUP BY 分组依据
HAVING 过滤条件
ORDER BY 排序的字段
LIMIT 限制显示的条数
];
为了方便理解我们往student表中再增加几条记录
INSERT INTO student (name,sex,age,admission_date,remark) VALUES('赵二',1,18,NOW(),'矮个子');
INSERT INTO student (name,sex,age,admission_date,remark) VALUES('钱一',2,18,NOW(),'矮个子');
INSERT INTO student (name,sex,age,admission_date,remark) VALUES('孙六',1,20,NOW(),'矮个子');
增加后数据库里总共5条记录。
下面我们就语法结构做下讲解:
[]内的是非必须的语句,WHERE 我们之前已经用到了,用于限定符合条件的记录,where ID=1 表示ID等于1的记录,如果有多个限定条件可以用AND 或者是 or 连接,表示and同时满足的意思,or表示满足其中一个就好。
例子:
SELECT * FROM student WHERE id=2
SELECT * FROM student WHERE id=2 and sex=1 and age=18(注意空格)
SELECT * FROM student WHERE id=2 and sex=1 and age=19(注意空格)
and 表示同时满足,如果有一个条件不满足,则找不到记录!
SELECT * FROM student WHERE id=2 OR sex=1 OR age=19 (注意空格)
OR 表示或许的意思 只要一个条件满足就好
where语句后可以出现的条件符号:
> 、< 、<= 、>= 、= 、<>(含义同数学中的含义)
例子:查询年龄大于18岁的同学。
SELECT * FROM student WHERE age>18(其余符号,大家可以自主在SQLYog中练习)
BETWEEN...AND (表示一个数值范围)
例子:查询年龄18到20岁之间的同学。
SELECT * FROM student WHERE age BETWEEN 18 AND 20
IN( 集合)
例子:查询编号为2,3,4的同学
SELECT * FROM student WHERE ID IN(2,3,4)
图片里故意写了一个1,1的记录不存在,则不会查询出来,同样,如果2,3,4不存在也不会展示出来。
LIKE:模糊查询
例子:
查询姓李的同学
SELECT * FROM student WHERE NAME LIKE'李%'
%表示通配符,李%表示‘李’开头的数据
查询备注中有“个子的同学”
SELECT * FROM student WHERE remark LIKE'%个子%'
两个%%中间表示只要包含某个特定字符就满足条件。
DISTINCT
查询年龄,按年龄去重
SELECT DISTINCT age FROM student
DISTINCT是按某个列名去重,如果加了其他数据不同的列名,达不到效果
GROUP BY 分组条件:
查询性别和名字,按性别分组:
SELECT sex,name FROM student GROUP BY sex
如果有多个分组条件用逗号分隔,查询性别和姓名,按性别和姓名分组
SELECT sex,name FROM student GROUP BY sex,name
HAVING:
对数据做过滤条件,如果语句中有group by 出现,则必须跟在group by后面,否则会有语法错误。
当语句里没有 group by时,和where 含义差不多,只是很少这样写。
查询性别和姓名,按性别和姓名分组后,并且要求sex=1(男性)的数据
SELECT sex,name from student group by sex , name having sex=1
ORDER BY
排序的意思,默认是升序(ASC),也可以指明是降序(DESC)
例子:
查询性别和姓名,按性别和姓名分组后,并且要求sex=1(男性)的数据,按姓名升序排列
SELECT sex,NAME FROM student GROUP BY sex,NAME HAVING sex=1 ORDER BY NAME
或者
SELECT sex,NAME FROM student GROUP BY sex,NAME HAVING sex=1 ORDER BY NAME ASC
查询性别和姓名,按性别和姓名分组后,并且要求sex=1(男性)的数据,按姓名降序排列
SELECT sex,NAME FROM student GROUP BY sex,NAME HAVING sex=1 ORDER BY NAME DESC
Limit
限制条件:
表示需要多少条数据
注意:当limit条件后跟随1个数字时,表示最多返回满足条件的多少条数据。
当limit条件后跟随2个数字(数字间用逗号分隔),表示从满足条件的第几条数据开始,一共最多返回多少条数据。
特别注意:满足条件的记录条数0,代表第一条记录。
例子:
查询性别和姓名,按性别和姓名分组后,并且要求sex=1(男性)的数据,按姓名降序排列,只返回第一条数据
SELECT sex,NAME FROM student GROUP BY sex,NAME HAVING sex=1 ORDER BY NAME DESC LIMIT 1
查询性别和姓名,按性别和姓名分组后,并且要求sex=1(男性)的数据,按姓名降序排列,从第一条数据开始,返回两条数据
接下来我们讲解多表查询
准备工作
我们先建立两张表课程表
CREATE TABLE `test01`.`CLASS`(
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '课程编号',
`C_NAME` VARCHAR(50) NOT NULL COMMENT '课程名称',
PRIMARY KEY (`ID`)
) ENGINE=INNODB CHARSET=utf8;
给课程表增加记录
INSERT INTO CLASS (C_NAME) VALUES('MYSQL基础');
INSERT INTO CLASS (C_NAME) VALUES('JAVA基础');
INSERT INTO CLASS (C_NAME) VALUES('HTML基础');
学生选课表 用于表示学生和课程之间的选学关系
CREATE TABLE `student_class` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '学生课程表ID,主键',
`S_ID` bigint(20) DEFAULT NULL COMMENT '学生编号',
`C_ID` bigint(20) DEFAULT NULL COMMENT '课程编号',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注意:STUDENT_CLASS 表中的C_ID的值和CLASS表的ID对应
STUDENT_CLASS 表中的S_ID的值student表的ID对应
增加记录
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(2,1);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(2,2);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(2,3);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(3,2);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(3,3);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(4,3);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(5,1);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(5,2);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(5,3);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(6,2);
多表连接查询:当某次查询结果需要用到多个表的数据的时候,就需要用到多表连接查询。
最简单的表连接查询为内连接查询。
内连接语法 :
select 需要查询的字段名 from 表1 INNER JOIN 表2 ON 表1.字段名=表2.字段名 INNER JOIN 表三 ON
表1.字段名=表3.字段名(或者是表2.字段名=表3.字段名)
[
WHERE 约束条件
GROUP BY 分组依据
HAVING 过滤条件
ORDER BY 排序的字段
LIMIT 限制显示的条数
];
注意:按需求去做表连接查询,有几个连接就写几个连接,内连接会返回连接两边都同时满足的记录。
下面就是使用内连接查询的例子:
1. 查询每个学生的基本信息和选课情况。
例子:
SELECT s.*,c.* FROM student s INNER JOIN student_class cs ON s.id =cs.s_id INNER JOIN class c ON cs.c_id=c.id
内连接也可以用=号代替推荐第二中写法,较为简洁。
SELECT s.*,c.* FROM student s, class c, student_class cs WHERE s.ID=CS.S_ID AND CS.C_ID= c.ID
2. 查询编号为2的学生的基本信息和选课情况
SELECT s.*,c.* FROM student s, class c, student_class cs WHERE s.ID=CS.S_ID AND CS.C_ID= c.ID AND s.id= 2
LEFT JOIN (左外连接)
数据准备:往学生选课表中插入三条学生表中不存在的记录
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(7,1);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(7,2);
INSERT INTO STUDENT_CLASS (S_ID,C_ID) VALUES(7,3);
使用左外连接查询学生的选课情况:
SELECT c.* ,s.*,cs.* FROM student_class cs LEFT JOIN student s ON s.id =cs.s_id LEFT JOIN class c ON cs.c_id=c.id
左外连接:以写在JOIN关键字左边的表为基准,和JOIN关键字右边的表做关联,如果JOIN关键字左边表里的数据存在,则会作为一条记录存在,如果右边的表里不存在相关联的数据,则用NULL值补充。
右外连接
使用右外连接查询学生的选课情况:
SELECT c.* ,s.*,cs.* FROM student s RIGHT JOIN student_class cs ON s.id =cs.s_id RIGHT JOIN class c ON cs.c_id=c.id
右外连接:以写在JOIN关键字右边的表为基准,和JOIN关键字左边的表做关联,如果JOIN关键字右边表里的数据存在,则会作为一条记录存在,如果左边的表里不存在相关联的数据,则用NULL值补充。
注意:LEFT JOIN 和RIGHT JOIN的写法是看顺序的,大家看例子的时候要注意语句的例子的写法。
子查询
IN 子查询
SELECT 字段名 FROM 表名 where 字段名 IN(SELECT 字段名 FROM 表名)
例子:
查询已经选课的学生基本信息
SELECT * FROM student WHERE id IN(SELECT s_id FROM STUDENT_CLASS)
小作业
1. 查询编号为2的学生基本信息。
2. 查询姓王的学生基本信息。
3. 统计每个学生的名字和选择了几门课程。(小提示:内连接,分组)
4. 统计选择了两门课以上的学生姓名和选择的课程数量。(小提示:内连接,分组,having)
5. 统计选择了两门课以上的学生姓名和选择的课程数量,按选课数量倒排返回2条记录。(小提示:内连接,分组,having,limit)
6. 统计选择了两门课以上的学生姓名和选择的课程数量,按选课数量倒排从第一条记录开始返回2条记录。(小提示:内连接,分组,having,limit)