数据的存储方式?
方式一:
存入到内存
优点:内存的擦写数据的数据是非常快
缺点:一个进程的关闭或者中断即内存清空,无法永久的保存
方式二:
存入到硬盘
优点:可以永久的保存
缺点:因为硬盘的擦写是频繁的进行I/O的操作,所以效率会比较低
方式三:
存入到数据库软件
优点:数据能够永久的进行保存
查询数据非常的方便
执行的效率还不错
什么是数据库
数据库(DB):是长期存储在计算机上的一款软件
市面上常见的数据库:
Oracle:是甲骨文旗下的产品,可以满足市面所有中大型的应用,和Java的兼容性特别好
SQL Server:微软的产品,目前市面上很少使用,和.NET(C#)的兼容性最好
DB2:IBM的产品,和IBM配套的服务器兼容性最好
Mysql:甲骨文公司的产品,因为是开源的,稳定性非常好 而且是市面上所有中小型公司必备数据库(免费)
SQL概述
SQL被称之为结构化查询语言,市面上基本所有的关系型数据都采用了SQL的最标准的结构性写法。
SQL的方言,其实就是在原来标准的SQL语言上 特定的数据库厂商加上的特点的SQL语句,
我们学习SQL,需要考虑每一款数据库提供的不同的方言
SQL的分类
DDL(数据定义语言):用来操作数据的库、表、列相关的操作
DML(数据操作语言):来对数据库进行数据的记录,比如数据添加、修改
DCL(数据控制语言):主要用于数据库的权限管理和安全级别控制
DQL(数据查询语言):主要用于数据的数据查询操作
DDL来操作数据库(create、alter、drop)
登录
mysql -u root -p
Enter password: *****
查看数据库
查看当前账户所有数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema | 数据库的元数据的存储
| mysql | 数据库用户信息或者软件配置信息
| performance_schema | 数据库的运行性能数据以及软件的运行数据
| test | 测试数据库
+--------------------+
查看指定数据库的定义信息
show create database mydb1;
创建数据库
使用默认字符集编码创建
create database mydb1;
使用指定字符集编码创建
create database mydb2 character set gbk;
修改已创建数据库的字符集编码(修复数据库编码)
alter database mydb1 default character set gbk;
删除数据库
drop database mydb2;
切换数据库
use mydb1;
查看当前所在数据库
select database();
课堂练习:
## 数据库创建
### 创建一个名字为mydb1的数据库
### 创建一个使用utf8字符集编码的数据库(mydb2)
### 将mydb2的字符集编码修改为gbk
## 数据库的删除
### 将mydb2删除
## 数据库的查看
### 查看所有数据库
### 查看当前所在数据库
### 查看mydb1的定义信息
创建一张表
create table 表名(字段类型 字段名,字段类型 字段名...);
create table studen(id int,name varchar(20),age int);
添加表字段
alter table 表明 add column 添加的字段名 添加的字段类型;
alter table studen add column gender varchar(1);
修改表字段
alter table studen modify column 修改的字段名 修改的字段类型;
alter table studen modify column gender varchar(2);
修改表字段名
alter table studen change column 修改名字的字段名 修改名字的字段类型;
alter table studen change column gender sex varchar(2);
修改表名称
alter table 原表名称 rename to 新表名称;
alter table studen rename to student;
删除表
drop table 表名称;
drop table student;
查看表
desc studen;
查看当前数据库里面的所有表
show tables;
DML来操作数据库的数据(增、删、改)
DML的数据插入操作:INSERT
语法:
INSERT INTO 表名(列名1,列名2...) VALUES(列值1,列值2);
-- 根据指定列进行值插入
INSERT INTO studen(id,name,age) VALUES (1,'TOOBUG',15);
-- 对数据表全部插入(这种方式必须保证你VALUES的值必须一一配对字段的顺序以及数据类型)
INSERT INTO studen VALUES (1,'TOOBUG',15);
修改数据:UPDATE
语法:
-- 需求,将所有的toobug改成龙哥
-- 这种方式不合理,因为所有的name都会被修改成龍哥
UPDATE 表名 SET 修改的字段 = 修改的值;
UPDATE studen SET name = '苏绪';
-- 带限定条件的修改
UPDATE 表名 SET 修改的字段 = 修改的值 WHERE 逻辑条件;
UPDATE studen SET age = 25 WHERE ID = 2;
-- 带多个条件的修改
UPDATE studen SET name = '二哈',age = 40 WHERE age = 15;
删除数据:DELETE
语法:
这种方式会=将表里的数据全部删除,因为没有限制条件(慎用)
DELETE FROM studen;
-- 根据指定条件进行删除
DELETE FROM studen WHERE id = 3;
-- 使用TRUNCATE进行删除
TRUNCATE TABLE studen;
--DELETE和TRUNCATE的区别?
DELETE删除的是表里的数据
TRUNCATE是把表直接DROP掉,然后在创建一张空的新表
DELETE删除的数据是可以进行回滚(即可以恢复)
TRUNCATE由于是删除物理文件,然后在新创建物理文件,所以里面的数据无法找回
DELETE既可以删除指定数据,也可以删除全表数据
TRUNCATE只能删除全表数据
DELETE删除的数据,不会直接影响索引和增长约束
TRUNCATE删除的数据,因为是库级删除,所有的索引和约束会重新建立
题目训练:
创建一张employee表,字段如下(id,姓名,薪水)
将所有员工的薪水修改为5000
将姓名为toobug的员工薪水修改为200
将id为3的员工在原来薪水的基础上加上1000元
关于无法插入中文的问题:
查看数据库的具体编码信息
show variables like 'character%';
临时修改客户端和服务端的编码信息
set character_set_client=gbk;
set character_set_results =gbk;
DQL数据查询语言(重要)
查询所有字段(这里返回的其实是一张虚拟表,而不数据)
SELECT * FROM studen;
上面这段SQL语句的执行的顺序?
FROM -> SELECT
根据指定字段进行查询
SELECT NAME,age FROM studen;
查询时指定别名
SELECT NAME AS '姓名',age AS '年龄' FROM studen;
SELECT NAME '姓名',age '年龄' FROM studen;
-- 在指定别名的时候,最好是不用加上单引号 因为加上单引号也就也为无法通过别名进行排序
-- 如果你的别名带上了特殊符号,以及使用了关键字 请务必加上单引号
SELECT NAME 姓名,age 年龄 FROM studen;
-- 在原来的虚拟表新增一个虚拟列(常量列)
SELECT NAME 商品名称,pric 价格,t_pric 批发价格,(pric-t_pric) AS '利润价格' FROM pric;
去除重复记录
SELECT DISTINCT NAME FROM pric;
SELECT DISTINCT(NAME) FROM pric;
条件查询(WHERE)
查询ID为3,且年龄为20岁以上的员工
SELECT * FROM emp WHERE id = 3 AND age > 20;
查询ID为3,或者工资大于5000的员工
SELECT * FROM emp WHERE id = 3 OR sal > 5000;
比较条件 > < >= <= = != <>
-- 查询奖金范围在2000~6000的员工
SELECT * FROM emp WHERE comm > 2000 AND comm < 6000;
SELECT * FROM emp WHERE comm BETWEEN 2000 AND 6000;
查询job字段为空的员工
-- NULL和空字符串的区别
-- NULL字段里面没有数据 IS NULL,IS NOT NULL(判断不为空)
-- 空字符串,里面其实存在数据,但是是空的 ='',<>''
SELECT * FROM emp WHERE job IS NULL;
SELECT * FROM emp WHERE job='' ;
SELECT NAME FROM emp WHERE job<>'' AND job IS NOT NULL;
模糊查询
关键字 LIKE
LIKE后面跟上匹配语句
%:表示后面的任意字符(0-多个)
_:表示任意一个字符
-- 查询所有姓马的员工
SELECT * FROM emp WHERE NAME LIKE '马%';
-- 查询姓名当中包含'小'的员工
SELECT * FROM emp WHERE NAME LIKE '%小%';
-- 查询姓马,且名字只有两个字的员工
SELECT * FROM emp WHERE NAME LIKE '马__';
聚合函数
聚合函数的作用就是对一组数据进行统计的聚合,最后返回一个值
COUNT:统计一组数据的具体记录数
-- 查询出我一共有多少个商品
SELECT COUNT(*) AS 商品总数 FROM pric;
MAX:统计一组数据的最大值
-- 查询所有商品最高价格
SELECT MAX(pric) FROM pric;
MIN:统计一组数据的最小值
-- 查询商品的最小价格
SELECT MIN(pric) FROM pric;
SUM:统计一组数据的总和
-- 查询商品价格的总和
SELECT SUM(pric) FROM pric;
AVG:统计一组数据的平均值
-- 查询商品价格的平均值
SELECT AVG(pric) FROM pric;
-- 查询商品的最小价格/最大价格以及商品的成本价格总和
SELECT MIN(pric),MAX(pric),SUM(pric) FROM pric;
查询商品的记录数,在Java当中进行接收一定要使用long类型 COUNT会自动排除NULL值的数据
分页查询
假分页/逻辑分页/内存分页
一次性从数据查询出所有的数据,将这些数据存放在内存当中(List的集合当中),每一次翻页的时候都从内存去取出数据。
特点:翻页速度非常快,但是每一次断点都需要从数据库重新取出数据,而且极容易造成内存溢出。
真分页/物理分页/数据库分页
每一次翻页的时候,都从数据库截取指定的条数,比如0-9/10-19....
特点:如果每页显示的数据非常多,速度会比较慢,但是不会造成内存溢出
MySQL的分页
LIMIT 从多少行开始查询,每一次查询执行多少行;
-- 第一页
SELECT * FROM emp LIMIT 0,3;
-- 第二页
SELECT * FROM emp LIMIT 3,3;
-- 第三页
SELECT * FROM emp LIMIT 6,3;
-- Java中如何利用分页的规则
-- int pageSize = 3;//每一页显示的数量
-- int currentPage = 1;//当前页数
SELECT * FROM emp LIMIT (currentPage-1)*pageSize,pageSize;
分组查询
统计各个区的人数是多少[GROUP BY]
SELECT AREA AS 地区,COUNT(*)AS 人数 FROM emp GROUP BY AREA;
查询工资大于2000的人数[GROUP BY]
SELECT sal AS 工资,COUNT(*)AS 人数 FROM emp WHERE sal > 2000 GROUP BY AREA;
查询人数大余2个人的地区(HAVING)
SELECT `area`,COUNT(*) FROM `emp` GROUP BY `area` HAVING COUNT(*) > 2;
-- 错误代码
SELECT AREA,COUNT(*) FROM EMP WHERE COUNT(*) > 2 GROUP BY AREA;
员工工资从小到大进行排序(默认缺省值)[ORDER BY]
SELECT * FROM emp ORDER BY sal ASC;
员工工资从大到小进行排序[ORDER BY]
SELECT * FROM emp ORDER BY sal DESC;
执行顺序:FROM -> WHERE -> SELECT -> GROUP BY
HAVING和WHERE的区别?
HAVING是分组后的条件刷选,主要使用在GROUP BY子句后面
WHERE是分组钱的条件刷选,主要使用在GROUP BY子句执行的前面
数据库的设计
需求分析:原始需求(客户提出来的)
业务需求:登录需要几张表?几个字段?字段类型?字段长度?
数据库的三大范式设计(是每一个程序员必须掌握和了解的数据库设计的最基础的理念)
第一范式:每一张表的字段名都必须是具备原子性(每一个字段都必须是一个不可分割的单元)
违背第一范式
+---------------------------------+
id name
+---------------------------------+
1 toobug | 张飞龙
2 张三|二狗子
+---------------------------------+
查询现用名姓张的学生 张%
符合第一范式
+---------------------------------+
id name old_name
+---------------------------------+
1 toobug 张飞龙
2 张三 二狗子
+---------------------------------+
第二范式:在第一范式的基础上,要求表除主键字段以外的字段必须和该表存在绝对的依赖关系
违反第二范式
+---------------------------------+
id 姓名 订单
+---------------------------------+
1 toobug 001
2 张三 002
+---------------------------------+
符合第二范式
-- 员工表
+---------------------------------+
id 姓名
+---------------------------------+
1 toobug
2 张三
+---------------------------------+
-- 订单表
+---------------------------------+
id 订单
+---------------------------------+
1 001
2 002
+---------------------------------+
第三范式:在第二范式的基础上,要求表除主键字段以外的字段只能和主键有直接决定的依赖关系
违反第三范式
-- 员工表
+---------------------------------+
id 姓名 部门
+---------------------------------+
1 toobug 软件开发部
2 张三 软件开发部
3 张三 软件开发部
4 张三 软件开发部
+---------------------------------+
符合第三范式
-- 员工表
+---------------------------------+
id 姓名 部门
+---------------------------------+
1 toobug 1
2 张三 1
3 张三 1
4 张三 1
+---------------------------------+
-- 部门表
+---------------------------------+
id 姓名
+---------------------------------+
1 软件开发部
2 基础架构部
3 视图处理部
+---------------------------------+
数据的约束
给表添加一些数据上面的条件约束,主要的作用就是约束用户对数据操作的准确性
默认值约束[DEFAULT]
当前表在某个字段没有插入数据的时候,可以适当的赋予默认的插入
默认约束必须是插入字段没有插入值的时候才会生效
需求:当gender字段没被插入数据的时候,默认显示女 CREATE TABLE test( NAME VARCHAR(20), gender VARCHAR(2) DEFAULT '女' );
INSERT INTO test(NAME,gender) VALUE('toobug','男');
INSERT INTO test(NAME) VALUE('橘梨纱');
非空约束[NOT NULL]
当在某个字段限制非空约束的时候,以后再任何情况,该字段必须存在数据,不能是NULL
CREATE TABLE test(
NAME VARCHAR(20) NOT NULL,
gender VARCHAR(2)
);
INSERT INTO test(NAME,gender) VALUE('toobug','男');
INSERT INTO test(gender) VALUE('女'); -- 违反约束
唯一约束[UNIQUE]
某个字段被限制唯一约束之后,该字段的数据值必须是唯一不重复的,否则将违反约束
-- 唯一约束
CREATE TABLE test(
id INT UNIQUE,
NAME VARCHAR(20) NOT NULL,
gender VARCHAR(2)
);
INSERT INTO test(ID,NAME,gender) VALUE(1,'toobug','男');
INSERT INTO test(ID,NAME,gender) VALUE(1,'','女'); -- 违反约束
主键约束(重要[非空+唯一])[PRIMARY KEY]
1.通常只在创建一个表的时候,我们都会加上一个id的字段,这个字段的本意就是保证每一条数据的准确性和唯一性(唯一、非空),所以我们需要使用主键
2.我们一般设置主键的方式有两种,一直被称之为业务主键,一种被称之为自然主键
业务主键:通常使用某个业务字段作为主键参考(name/sid/password)
自然主键:通常使用一个无意义的字段,自然生长 不去干预(id)
在实际的开发当中,我们尽可能不去使用业务字段作为表主键,因为业务的需求变化太大,一旦业务需求更改,也就意味着表主键失效,业务字段很容易出现字段重复的问题
我们推荐的方式,一般是给每一张表设定一个id字段,这个字段不存在任何的业务意义,而且这个字段最好是自增长
-- 主键约束
CREATE TABLE test(
id INT PRIMARY KEY,
NAME VARCHAR(20),
gender VARCHAR(2)
);
INSERT INTO test(ID,NAME,gender) VALUE(1,'toobug','男');
外键约束(重要)[PRIMARY KEY]
什么情况下需要使用到外键约束?
当我们存在两张或两张表以上的时候,且这张表的某个字段密切关联着另外一张表的数据,则需要使用到外键约束
什么情况下可能会出现两张表?
出现数据冗余的时候
-- 员工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
deptid INT,
-- constraint 外键名称 foreign key(外键字段) references 主键表(主键表字段);
CONSTRAINT fk_dept_emp FOREIGN KEY(deptid) REFERENCES detp(id)
)
-- 创建一个商品表和分类表
多表之间的建表原则
一对多:商品和分类
建表原则:在多一方建立外键,在一的一方建立主键,使用外键关联主键
多对多:老师和学生,学生和课程
建表原则:建立一张中间表,将多对多的关系拆成一对多的关系,中间表最少要有两个外键
一对一:班级和班长,一个公民对应一个身份证
将一对一的关系,直接当成是一条数据进行处理,或者说直接当成一对多的关系也没问题,但凡一张表只要包含主键,那么就是一对一的关系
多表查询
-- 交叉查询造成了笛卡尔积查询(左表数据 * 右表数据 = 结果数据)
SELECT * FROM emp,detp;
-- 解决笛卡尔积的问题(内连接查询) 使用最多的
SELECT e.name,d.dname FROM emp e,detp d WHERE e.id = d.id;
-- 内连接查询方式二
SELECT
e.name,d.dname
FROM
emp e
INNER JOIN
dept d
ON
e.id = d.id;
-- 左外连接查询
-- 以左表作为显示主体,右边的显示数量将参考左表进行显示
-- 研发部 toobug
-- 技术部 mayun
-- 研发部 null
SELECT d.dname,e.name
FROM detp d
LEFT OUTER JOIN emp e
ON d.id = e.id;
-- 右外连接查询
-- 以右表作为显示主体,左边的显示数量将参考右表进行显示
-- 研发部 toobug
-- 技术部 mayun
-- 研发部 null
SELECT e.name,d.dname
FROM detp d
RIGHT OUTER JOIN emp e
ON d.id = e.id;
-- 子查询
SELECT * FROM emp WHERE id = 4;
-- 查询大于公司平均工资的员工姓名
-- 计算平均工资
SELECT AVG(sal) FROM emp;
-- 计算大于平均工资的员工
SELECT NAME,sal FROM emp WHERE sal > (SELECT AVG(sal) FROM emp);
-- 计算出工资比马云还要高的员工
SELECT sal FROM emp WHERE NAME = '马云';
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE NAME = '马云');
训练题:
-- 查询每个部门的部门编号,总人数,平均工资
-- 查询与TOOBUG在同一个部门的员工
-- 查询工资比马马云少的员工所在部门的人数
-- 查询每个部门薪水最高的员工所有信息
-- 查询所有部门编号为2的员工信息
-- 设计表
-- 账号
-- 商品
-- 分类
-- 要求商品必须存在由哪个账户进行发布的