为了介绍关系模型,以MySQL数据为例。
#安装mariadb
> yum install mariadb-server
#启动服务
> systemctl start mariadb.service
#开机启动
> systemctl enble mariadb.service
# 为了安全设置Mysql服务
> mysql_secure_installation
# 数据库密码登录
> mysql -u root -p
# 显示所有数据库
mysql> show databases;
# 创建用户并授权
mysql> grant all on *.* to 'xdd'@'%' identified by 'xdd';
mysql> flush privileges;
# 导入测试脚本
> mysql -u root -p < test.sql
SQL是结构化查询语言Structured Query Language。1987年被ISO组织标准化。
所有主流的关系型数据库都支持SQL,NoSQL也有很大一部分支持SQL。
SQL语句分为:
语言规范
/*注释内容*/
-- 注释内容
GRANT授权,REVOKE撤销
GRANT ALL ON employees.* TO 'xdd'@'%' IDENTIFIED by 'xdd';
REVOKE ALL ON *.* FROM xdd;
*
为通配符,代指任意库或者任意表。*.*
所有库的所有表。employess.*
表示employees库下所有的表%
为通配符,它是SQL语句的通配符,匹配任意长度字符串删除用户(慎用)
DROP USER xdd;
创建数据库
CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE DATABASE IF NOT test CHARACTER SET utf8;
删除数据库
DROP DATABASE IF EXISTS gogs;
创建表
CREATE TABLE `xddtable` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` enum('M','F') NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DESC查看列信息
{DESCRIBE | DESC} tb|_name [col_name | wild]
DESC xddtable;
DESC xddtable '%name'
DROP DATABASE IF EXISTS test;
CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
use test;
CREATE TABLE `reg` (
`id` int(11) NOT NULL,
`loginname` varchar(50) NOT NULL,
`name` varchar(64) DEFAULT NULL,
`password` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
) Engine = InnoDB
类型 | 含义 |
---|---|
tinyint | 1字节,带符号的范围是[-128,127]。无符号的范围是[0,255]。 bool或boolean,就是tinyint,0表示假,非0表示真 |
smallint | 2字节,带符号的分为是[-32768,32767]。无符号的范围是[0,65535] |
int | 整形,4字节,同Integer,带符号的范围是[-21474483648,2147483647]。无符号的范围是[0,4294967295] |
bigint | 长整形,8字节,同Integer,带符号的范围是[-9223372036854775808,9223372036854775807]。无符号的范围是[0,18446744073709551615] |
float | 单精度浮点数精确到大约7位小数位 |
double | 双精度浮点数精度确到大约15位小数位 |
DATE | 日期。支持的范围为’1000-01-01’到’9999-12-31’ |
DATETIME | 支持的范围是’1000-01-01 00:00:00’到’9999-12-31 23:59:59’ |
TIMESTAMP | 时间戳。范围是’1970-01-01 00:00:00’到2037年 |
char(M) | 固定长度,右边填充空格以达到长度要求。M为长度,范围为[0-255]。 M指代字符个数 |
varchar(M) | 变长字符串。M表示最大列长度。M的范围是[0-65535]。但不能突破行最大字节数65535 |
text | 大文本。最大长度为65535( 2 16 − 1 2^{16}-1 216−1)个字符 |
BLOB | 大字节。最大长度为65535( 2 16 − 1 2^{16}-1 216−1)字节的BLOB列 |
注意:在关系中,属性的顺序并不重要。理论上,元组顺序也不重要,但是由于元组顺序与存储相关,会影响查询效率。
限定了表中字段的取值范围
PRIMARY KEY约束定义了主键,就定义了主键约束。主键不重复且唯一,不能为空。
设定值 | 说明 |
---|---|
CASCADE | 级联,从父表删除或更新会自动删除或更新子表中匹配的行 |
SET NULL | 从父表删除或更新行,会设置字表中的外键为NULL,但必须保证字表列没有指定NOT NULL,也就是说子表的字段可以为NULL才行。 |
RESTRICT | 如果从附表删除主键,如果子表引用了,则拒绝对父表的删除或更新操作 |
NO ACTION | 标准SQL的关键字,在MySQL中与RESTRICT相同。拒绝对父表的删除或更新操作 |
数据库建立,需要搜集用户需求,设计符合企业要求的数据模型。而构建这种模型需要方法,这种方法需要称为E-R实体-联系建模。也出现了一种建模语言–UML(Unified Modeling Language)统一建模语言。
实体Entity:现实世界中具有相同属性的一组对象,可以是物理存在的事物或抽象的事物。
联系Relationship:实体之间的关联集合。
实体间联系类型
假设有实体部门,实体员工
类型 | 描述 | 解决方案 |
---|---|---|
一对多联系1:n | 一个员工属于一个部门,一个部门有多个员工 | 员工外键:部门主键 |
多对多联系m:n | 一个员工属于多个部门,一个部门有多个员工 | 建立第三表 |
一对一联系1:1 | 假设有实体管理者,一个管理者管理一个部门,一个部门只有一个管理者 | 字段健在哪张表都行 |
Insert语句 插入语句
INSERT INTO 表名[(插入的字段名,插入的字段名,...)] VALUES (对应的字典内容,对应的字段内容,...)
INSERT INTO table_name (col_name,...) VALUES (value1,...);
-- 向表中插入一行数据,自增字段、缺省值字段、可为空字段可以不写
INSERT INTO table_name SELECT ... ;
-- 将select查询的结果插入到表中
INSERT INTO table_name (col_name1,...) VALUES (value1,...) ON DUPLICATE KEY UPDATE col_name1=value1,...;
-- 如果主键冲突、唯一键冲突就执行update后的设置。这条语句的意思,就是主键不在新增记录,主键在就更新部分字 段。
INSERT IGNORE INTO table_name (col_name,...) VALUES (value1,...);
-- 如果主键冲突、唯一键冲突就忽略错误,返回一个警告。
INSERT INTO reg (loginname,`name`,`password`) VALUES ('tom','tom','tom');
INSERT INTO reg (id,loginname,`name`,`password`) VALUES (5,'tom','tom','tom');
INSERT INTO reg (id,loginname,`name`,`password`) VALUES (5,'tom','tom','tom') ON DUPLICATE KEY UPDATE name = 'jerry'
Update语句,修改语句
UPDATE 需要更新的表名 SET 更新的指段名=更新的值 ,... WHERE 条件
UPDATE [IGNORE] tbl_name SET col_name1=expr1 [,col_name2=expr2,...][WHERE where_defintion]
-- IGNORE 意义同Insert语句
UPDATE reg SET name='张三' WHERE id = 5;
-- 注意这一句非常危险,会更新所有数据
UPDATE reg SET name = 'ben';
-- 更新一定要加条件
UPDATE reg SET name = 'ben',password = 'benpwd' WHERE id = 1;
Delete语句,删除语句
DELETE FROM 表名 [WHERE 条件]
DELETE FROM tbl_name [WHERE where_definition]
-- 删除复合条件的记录
--删除一定要有条件,否则非常危险
DELETE FROM reg WHERE id = 1;
Select语句,查询语句
SELECT [DISTINCT] 字段名 FROM 表名 [WHERE 条件] [GROUP BY 需要分组的字段名 [HAVING 条件]] [ORDER BY 需要排序的字段名 [ASC | DESC]] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]
SELECT
[DISTINCT]
select_expr,...
FROM table_references
[WHERE where_definition]
[GROUP BY {col_name | expr | position}
[ASC | DESC],...[WITH ROLLUP]]
[HAVING where_definition]
[ORDER BY {col_name | expr | position}
[ASC | DESC],...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[FOR UPDATE | LOCK IN SHARE MODE]
select 1;
-- 最简单的查询
SELECT * FROM employees;
-- 字符串合并
SELECT emp_no,first_name + last_name FROM employees;
SELECT emp_no,CONCAT(first_name,' ',last_name) FROM employees;
-- AS 定义别名,可选。写AS是一个好习惯
SELECT emp_no as `no`,CONCAT(first_name,' ',last_name) name FROM employees emp;
Where 子句 条件
运算符 | 描述 |
---|---|
= |
等于 |
<> |
不等于 |
>、<、>=、<= |
大于、小于、大于等于、小于等于 |
BETWEEN | 在某个范围之内,between A and B 等价于[A,B] |
LIKE | 字符串模式匹配,% 表示任意多个字符,_ 表示一个字符 |
IN | 指定针对某个列的多个可能值 |
AND | 与 |
OR | 或 |
-- 条件查询
SELECT * FROM employees WHERE emp_no<10015 and last_name LIKE 'P%';
SELECT * FROM employees WHERE emp_no BETWEEN 10010 AND 10015 AND last_name LIKE 'P%';
SELECT * FROM employees WHERE emp_no in (10001,10002,10010);
Order by子句 排序
-- 降序
SELECT * FROM employees WHERE emp_no in (10001,10002,10010) ORDER BY emp_no DESC;
DISTINCT 去重
-- DISTINCT 使用
SELECT DISTINCT dept_no from dept_emp;
SELECT DISTINCT emp_no from dept_emp;
SELECT DISTINCT dept_no,emp_no from dept_emp;
Limit子句,分页
-- 返回5条记录
SELECT * FROM employees emp LIMIT 5;
-- 返回5条记录,偏移18条
SELECT * FROM employees emp LIMIT 5 OFFSET 18;
SELECT * FROM employees emp LIMIT 18,5;
聚合函数
函数 | 描述 |
---|---|
COUNT(expr) | 返回记录中记录的数目,如果指定列,则返回非NULL值的行数 |
COUNT(DISTINCT expr,[expr…]) | 返回不重复的非NULL值的行数 |
AVG([DISTINCT] expr) | 返回平均值,返回不同值的平均值 |
MIN(expr),MAX(expr) | 最小值,最大值 |
SUM([DISTINCT] expr) | 求和,DISTINCT返回不同值求和 |
-- 聚合函数
SELECT COUNT(*),AVG(emp_no),SUM(emp_no),MIN(emp_no),MAX(emp_no) FROM employees;
分组查询
-- 聚合所有
SELECT emp_no,SUM(salary),AVG(salary),COUNT(emp_no) from salaries;
-- 聚合被选择的记录
SELECT emp_no,SUM(salary),AVG(salary),COUNT(emp_no) from salaries WHERE emp_no <10003;
-- 分组
SELECT emp_no FROM salaries GROUP BY emp_no;
SELECT emp_no FROM salaries WHERE emp_no < 10003 GROUP BY emp_no;
-- 按照不同emp_no分组,每组分别聚合
SELECT emp_no,SUM(salary),AVG(salary),COUNT(emp_no) from salaries WHERE emp_no < 10003 GROUP BY emp_no;
-- HAVING子句对分组结果过滤
SELECT emp_no,SUM(salary),AVG(salary),COUNT(emp_no) from salaries GROUP BY emp_no HAVING AVG(salary) > 45000;
--使用别名
SELECT emp_no,SUM(salary),AVG(salary) AS sal_avg,COUNT(emp_no) FROM salaries GROUP BY emp_no HAVING sal_avg > 60000;
-- 最后对分组过滤后的结果排序
SELECT emp_no,SUM(salary),AVG(salary) AS sal_avg,COUNT(emp_no) FROM salaries GROUP BY emp_no HAVING sal_avg > 60000 ORDER BY sal_avg;
-- 分组
SELECT emp_no, MAX(salary) FROM salaries; -- 10001 88958
SELECT emp_no, MIN(salary) FROM salaries; -- 10001 40006
SELECT emp_no MIN(salary) FROM salaries GROUP BY emp_no;
-- 单表较为复杂的语句
SELECT
emp_no,
avg(salary) AS avg_salary
FROM
salaries
WHERE
salary > 70000
GROUP BY
emp_no
HAVING
avg_salary > 50000
ORDER BY
avg_salary DESC
LIMIT 1;
子查询
-- 子查询
SELECT * FROM employees WHERE emp_no in (SELECT emp_no from employees WHERE emp_no > 10015) ORDER BY emp_no DESC;
SELECT emp.emp_no,emp.first_name,gender FROM (SELECT * FROM employees WHERE emp_no > 10015) AS emp WHERE emp.emp_no < 10019 ORDER BY emp_no DESC;
链接查询join
-- 工资40行
SELECT * FROM salaries;
-- 20行
SELECT * FROM employees;
-- 800行
SELECT * FROM employees CROSS JOIN salaries;
--隐试链接,800行
SELECT * FROM employees, salaries;
注意: salaries和employees并没有直接的关系,做笛卡尔乘积只是为了看的清楚
内连接 inner join 可以省略为join
等值链接(join … on),只选择某些field相等的元组(行),使用On限定关联的结果
自然链接(NATURAL JOIN),特殊的等值链接,会去掉重复的列。用的少
-- 内连接,笛卡尔乘积 800行
SELECT * FROM employees JOIN salaries;
SELECT * FROM employees INNER JOIN salaries;
-- ON等值链接 40行
SELECT * FROM employees JOIN salaries ON employees.emp_no = salaries.emp_no;
-- 自然链接,去掉了重复列,且自行使用employees.emp_no = salaries.emp_no的条件
SELECT * from employees NATURAL JOIN salaries;
-- 左链接
SELECT * FROM employees LEFT JOIN salaries ON employees.emp_no = salaries.emp_no;
-- 有链接
SELECT * FROM employees RIGHT JOIN salaries ON employees.emp_no = salaries.emp_no;
-- 这个右链接等价于上面的左链接
SELECT * FROM salaries RIGHT JOIN employees on employees.emp_no = salaries.emp_no;
SELECT * FROM employees RIGHT JOIN salaries ON employees.emp_no = salaries.emp_no;
结果是先employees后salaries的字段显示,Right是看表的数据的方向,从salaries往employees看,以salaries为准,它的所有数据都显示
自链接:表,自己和自己链接
select manager.* from emp manager,emp worker where manager.empno = worker.mgr and worker.empno = 1;
select manager.* from emp manager inner join emp worker on manager.empno = worker.mgr where worker.empno = 1;
这两种技术,虽然是数据库高级内容,性能不错,但基本很少用了。它们移植性差,使用时占用的服务器资源,排错、维护不方便。最大的原因,不太建议把逻辑放在数据库中。
特性 | 描述 |
---|---|
原子性(atomicity) | 一个事务是一个不可分割的工作单位,事务中包括的所有操作要么全部做完,要么什么都不做 |
一致性(consistency) | 事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的 |
隔离性(isolation) | 一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰 |
持久性(durability) | 持久性也称为永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响 |
原子性:要求事务中的所有操作,不可分割,不能做了一部分操作,还剩一部分操作;
一致性:多个事务并行执行的结果,应该和事务排队执行的结果一致。如果事务的并行执行和多线程读写共享资源一样不可预期,就不能保证一致性。
隔离性:就是指多个事务访问共同的数据了,应该互不干扰。隔离性,指的是究竟在一个书屋处理期间,其他事务能不能访问的问题。
持久性:比较好理解,就是事务提交后,数据不能丢失。
MySQL的隔离级别
隔离性不好,事务的操作就会互相影响,带来不同严重程度的后果。隔离性好不好会带来如下问题:
有了上述问题,数据库就必须要解决,提出了隔离级别。隔离级别由低到高,如下表
隔离级别 | 描述 |
---|---|
READ UNCOMMITTED | 读取到未提交的数据 |
READ COMMITTED | 读取已经提交的数据,Oracle默认级别 |
REPEATABLEREAD | 可重复读,MySQL的默认隔离级别 |
SERIALIZABLE | 可串行化,事务间完全隔离,事务不能并发,只能串行执行 |
-- 设置会话级或者全局隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
{READ UNCOMMITTED | READ COMMITIED | REPEATABLE READ | SERIALIZABLE}
-- 查询隔离级别
SELECT @@global.tx_isolation;
SELECT @@tx_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 禁止自动提交
SET AUTOCOMMIT = 0
本质上来说没有区别,都是存放数据的地方。
但是数据库关注数据的持久化、数据的关系,为业务系统提供支持,事务支持;
数据仓库存储的数据是为了分析或者发掘而设计的表结构,可以存储海量数据。