目录
常用命令
连接本地数据库:mysql -uroot -p,接着输入密码。
修改密码:将root的密码改为123456:mysqladmin -uroot -p 旧密码 password 123456
创建一个数据库:mysql>create database <数据库名>;
显示数据库:mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
连接数据库:mysql> use test;
Database changed
表示正在使用一个名字叫做test的数据库。
删除数据库:drop database <数据库名>;
显示MySQL版本:mysql> select version();
显示当前时间:mysql> select now();
创建数据表:create table <表名> ( <字段名1> <类型1> [,..<字段名n> <类型n>]);
表插入数据:insert into <表名> [( <字段名1>[,..<字段名n > ])] values ( 值1 )[, ( 值n )];
删除数据表:drop table <表名>;
关于SQL语句的分类
DQL:
数据查询语言(凡是带有select关键字的都是查询语句)
select...DML:
数据操作语言(凡是对表当中的数据进行增删改的都是DML)
insert delete update
insert 增
delete 删
update 改这个主要是操作表中的数据data。
DDL:
数据定义语言
凡是带有create、drop、alter的都是DDL。
DDL主要操作的是表的结构。不是表中的数据。
create:新建,等同于增
drop:删除
alter:修改
这个增删改和DML不同,这个主要是对表结构进行操作。TCL:
是事务控制语言
包括:
事务提交:commit;
事务回滚:rollback;DCL:
是数据控制语言。
例如:授权grant、撤销权限revoke....
DQL
简单的单表查询:
查询一个字段:
select 字段名 from 表名;
查询两个字段,或者多个字段:
使用逗号隔开“,”
查询所有字段:
第一种方式:可以把每个字段都写上
select a,b,c,d,e,f... from tablename;
第二种方式:可以使用*
select * from dept;
第二种方式的缺点:1、效率低。2、可读性差。优点:快速查询
起别名:
使用as关键字起别名。mysql> select 原名 as 别名 from dept;as可以省略,但是要换成空格
注意:只是将显示的查询结果列名显示为别名,原表列名没变
记住:select语句是永远都不会进行修改操作的。(因为只负责查询)
数据库中的字符串都是采用单引号括起来。这是标准的。双引号不标准。
条件查询:
语法格式:
select
字段1,字段2,字段3....
from
表名
where
条件;
<>或!= 不等于
between … and …. 两个值之间, 等同于 >= and <=
注意:
使用between and的时候,必须遵循左小右大。
between and是闭区间,包括两端的值。
is null 为 null(is not null 不为空)
查询哪些员工的津贴/补助为null?
select empno,ename,sal,comm from emp where comm is null;
注意:在数据库当中null不能使用等号进行衡量。需要使用is null,因为数据库中的null代表什么也没有,它不是一个值,所以不能使用等号衡量。
and和or同时出现,and优先级较高。如果想让or先执行,需要加“小括号”,开发中,如果不确定优先级,就加小括号就行了。
in 包含,相当于多个 or (not in:不在这个范围中)
注意:in不是一个区间。in后面是具体的值。
查询薪资是800和5000的员工信息
select ename,sal from emp where sal = 800 or sal = 5000;
select ename,sal from emp where sal in(800, 5000);
模糊查询:
select ename from emp where ename like '%O%';
like
称为模糊查询,支持%或下划线匹配
%匹配任意多个字符, %a%:表示a前面和后面都可以有任意字符
下划线:任意一个字符。_a,表示第二个字符是a的
(%是一个特殊的符号,_ 也是一个特殊符号)
排序:
select ename,sal from emp order by sal;#默认为升序
select ename,sal from emp order by sal asc;#指定升序
select ename,sal from emp order by sal desc;#指定降序
#查询员工名字和薪资,要求按照薪资升序,如果薪资一样的话,再按照名字升序排列。
select ename,sal from emp order by sal asc,ename asc
#sal在前,起主导,只有sal相等的时候,才会考虑启用ename排序。
数据处理函数:
数据处理函数又被称为单行处理函数
单行处理函数的特点:一个输入对应一个输出。
多行处理函数。(多行处理函数特点:多个输入,对应1个输出!)
常见的单行处理函数
select lower(ename) as ename from emp;#转小写
select upper(name) as name from emp;#转大写
#substr 取子串(substr( 被截取的字符串, 起始下标,截取的长度))
#注意:起始下标从1开始,没有0
select substr(ename, 1, 1) as ename from emp;
#首字母大写,函数嵌套,concat连接
SELECT CONCAT( SUBSTR(ename,1,1),LOWER(SUBSTR(ename,2,LENGTH(ename)-1))) FROM emp
#length获取长度
select length(ename)as enamelength from emp;
#trim去除空格
select * from emp where ename = trim(' KING');
select round(1236.567, 1) as result from emp; #保留1个小数
select round(1236.567, -1) as result from emp; #保留到十位。
#rand()生成随机数
select round(rand()*100,0) from emp; // 100以内的随机数
#ifnull 可以将 null 转换成一个具体值
#ifnull函数用法:ifnull(数据, 被当做哪个值)。
case..when..then..when..then..else..end
当员工的工作岗位是MANAGER的时候,工资上调10%,当工作岗位是SALESMAN的时候,工资上调50%,其它正常。
注意:不修改数据库,只是将查询结果显示为工资上调
select ename,job, sal as oldsal,
(case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 else sal end)
as newsal from emp;
分组函数(多行处理函数):
多行处理函数的特点:输入多行,最终输出一行。
5个:count,sum,avg,max,min
必须先进行分组,然后才能用。如果你没有对数据进行分组,整张表默认为一组。
分组函数在使用的时候需要注意:
第一点:分组函数自动忽略NULL,不需要提前对NULL进行处理。
第二点:分组函数中count(*)和count(具体字段)的区别
count(具体字段):表示统计该字段下所有不为NULL的元素的总数。
count(*):统计表当中的总行数。(只要有一行数据count则++)
因为每一行记录不可能都为NULL,一行数据中有一列不为NULL,则这行数据就是有效的。
第三点:分组函数不能够直接使用在where子句中。
第四点:所有的分组函数可以组合起来一起用。
分组查询:
先进行分组,然后对每一组的数据进行操作。使用分组查询。
语法:
select
...
from
...
where
...
group by
...
order by
...
执行顺序:
1. from
2. where
3. group by
4. select
5. order by
为什么分组函数不能直接使用在where后面?
select ename,sal from emp where sal > min(sal);//报错。
因为分组函数在使用的时候必须先分组之后才能使用。
where执行的时候,还没有分组。所以where后面不能出现分组函数。select sum(sal) from emp; 这个没有分组,因为select在group by之后执行。所以不报错
/*找出每个工作岗位的工资和,
实现思路:按照工作岗位分组,然后对工资求和。*/
SELECT
SUM(sal),job
FROM
emp
GROUP BY
job
ORDER BY
sal
重点结论:在一条select语句当中,如果有group by语句的话,select后面只能跟:参加分组的字段,以及分组函数。其它的一律不能跟。
#找出每个部门的最高薪资
#实现思路:按照部门编号分组,求每一组的最大值。
SELECT
MAX(sal),deptno
FROM
emp
GROUP BY deptno
#找出“每个部门,不同工作岗位”的最高薪资
SELECT
deptno,job,MAX(sal)
FROM
emp
GROUP BY deptno ,job
#找出每个部门最高薪资,要求显示最高薪资大于3000
SELECT
deptno,MAX(sal)
FROM
emp
WHERE
sal>3000
GROUP BY
deptno
-----where和having优先选择where,where解决不了再用having-----
SELECT
deptno,MAX(sal)
FROM
emp
GROUP BY
deptno
HAVING
MAX(sal) > 3000;
#找出每个岗位的平均薪资,要求显示平均薪资大于1500的,除MANAGER岗位之外,
#要求按照平均薪资降序排。
SELECT
AVG(sal)AS avgsal,job
FROM
emp
WHERE
job<>'manager'
GROUP BY
job
HAVING
AVG(sal)>1500
ORDER BY
avgsal DESC;
把查询结果去除重复记录【distinct】
SELECT DISTINCT job FROM emp
/*distinct只能出现在所有字段的最前方*/
SELECT DISTINCT job,deptno FROM emp
/*distinct出现在job,deptno两个字段之前,表示两个字段联合起来去重*/
连接查询:
多张表联合起来查询数据,被称为连接查询。
根据表连接的方式分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右连接)
-------匹配的过程中,进行了筛选,匹配次数没有减少------
SELECT
ename,dname
FROM
emp, dept
WHERE
emp.deptno = dept.deptno;
----------------------------------------
/*表起别名。很重要。效率问题。空格表示as*/
SELECT
e.ename,d.dname
FROM
emp e, dept d
WHERE
e.deptno = d.deptno; //SQL92语法
内连接——等值连接:
/*查询每个员工所在部门名称,显示员工名和部门名*/
SELECT
d.dname,e.ename
FROM
dept d,emp e
WHERE
e.DEPTNO=d.DEPTNO //SQL92语法
/*sql92的缺点:结构不清晰,表的连接条件,和后期进一步筛选的条件,都放到了where后面。*/
-----------------------------------------------
SELECT
d.dname,e.ename
FROM
dept d
JOIN /*inner可以省略(带着inner可读性更好!!!一眼就能看出来是内连接)*/
emp e
ON
e.DEPTNO=d.DEPTNO //SQL99语法
/*sql99优点:表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续添加where*/
sql92的缺点:结构不清晰,表的连接条件,和后期进一步筛选的条件,都放到了where后面。
内连接——非等值连接:
/*找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级*/
SELECT
e.ename,e.sal,s.grade
FROM
salgrade s,emp e
WHERE
e.sal BETWEEN s.losal AND s.hisal
----------------------------------------
SELECT
e.ename,e.sal,s.grade
FROM
emp e
JOIN
salgrade s
ON
e.sal BETWEEN s.losal AND s.hisal ;
内连接——自连接:
/*查询员工的上级领导,要求显示员工名和对应的领导名*/
/*技巧:一张表看成两张表*/
SELECT
a.ename AS '员工名',b.ename AS '领导名'
FROM
emp a
JOIN
emp b
ON
a.mgr=b.empno;
外连接(右外连接)
/*right代表,将join关键字右边的这张表看成主表,主要是为了将
这张表的数据全部查询出来,捎带着关联查询左边的表。在外连接当中,
两张表连接,产生了主次关系。*/
SELECT
e.ename,d.dname
FROM
emp e
RIGHT JOIN
dept d
ON
e.deptno = d.deptno;
外连接(左外连接)
SELECT
e.ename,d.dname
FROM
dept d
LEFT OUTER JOIN #OUTER是可以省略的,带着可读性强。
emp e
ON
e.deptno = d.deptno;
外连接的查询结果条数一定是 >= 内连接的查询结果条数
/*查询每个员工的上级领导,要求显示所有员工的名字和领导名*/
select
a.ename as '员工名', b.ename as '领导名'
from
emp a
left join
emp b
on
a.mgr = b.empno;
连接多张表:
select
...
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
/*找出每个员工的部门名称以及工资等级,
要求显示员工名、部门名、薪资、薪资等级*/
SELECT
e.ename,e.sal,d.dname,s.grade
FROM
emp e
JOIN
dept d
ON
e.deptno=d.deptno
JOIN
salgrade s
ON
e.sal BETWEEN s.losal AND s.hisal
/*找出每个员工的部门名称以及工资等级,还有上级领导,
要求显示员工名、领导名、部门名、薪资、薪资等级*/
select
e.ename,e.sal,d.dname,s.grade,l.ename
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal
left join
emp l
on
e.mgr = l.empno;
子查询:
select语句中嵌套select语句,被嵌套的select语句称为子查询
select
..(select).
from
..(select).
where
..(select).
/*找出比最低工资高的员工姓名和工资*/
SELECT
ename,sal
FROM
emp
WHERE sal >
(SELECT
MIN(sal)
FROM
emp) ;
from子句中的子查询
注意:from后面的子查询,可以将子查询的查询结果当做一张临时表
/*找出每个岗位的平均工资的薪资等级*/
SELECT
t.*, s.grade
FROM
(SELECT job,AVG(sal) AS avgsal FROM emp GROUP BY job) t
JOIN
salgrade s
ON
t.avgsal BETWEEN s.losal AND s.hisal;
select后面的子查询(了解)
/*找出每个员工的部门名称,要求显示员工名,部门名*/
SELECT
e.ename,e.deptno,(SELECT d.dname FROM dept d WHERE e.deptno = d.deptno) AS dname
FROM
emp e ;
/*对于select后面的子查询来说,这个子查询只能一次返回1条结果,否则报错*/
union
/*查询工作岗位是MANAGER和SALESMAN的员工*/
select ename,job from emp where job = 'MANAGER'
union
select ename,job from emp where job = 'SALESMAN';
/*union的效率要高一些。对于表连接来说,每连接一次新表,
则匹配的次数满足笛卡尔积,成倍的翻。
但是union可以减少匹配的次数。在减少匹配次数的情况下,
还可以完成两个结果集的拼接。
union把乘法变成了加法运算
*/
limit(非常重要)
将查询结果集的一部分取出来。通常使用在分页查询当中。百度默认:一页显示10条记录
分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差。可以一页一页翻页看。
完整用法:limit startIndex, length
startIndex是起始下标,length是长度。
起始下标从0开始。
缺省用法:limit 5; 这是取前5.
/*取出工资排名在[3-5]名的员工*/
SELECT
ename,sal
FROM
emp
ORDER BY
sal DESC
LIMIT 2,3 ;
/*2表示起始位置从下标2第三条开始,
3表示长度
*/
分页:
/*每页显示pageSize 条记录*/
limit (pageNo-1)*pageSize , pageSize
DQL语句的总结:
select
...
from
...
where
...
group by
...
having
...
order by
...
limit
...
执行顺序?
1.from
2.where
3.group by
4.having
5.select
6.order by
7.limit..
DDL
DDL包括:(create drop alter)
建表:
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型
);
CREATE TABLE t_student (
NUM INT,
NAME VARCHAR (32),
sex CHAR(1),
age INT (3),
email VARCHAR (255)
) ;
varchar(最长255),可变长度的字符串,动态分配空间
char(最长255),定长字符串。
int(最长11)
bigint,数字中的长整型,相当于long
float、double
date,短日期类型 datetime,长日期类型
clob,字符大对象,超过255个字符的都要采用CLOB字符大对象来存储。
blob, 二进制大对象,例如插入一个图片、视频等。
DML
insert插入数据
语法格式:insert into 表名(字段名1,字段名2...) values(值1,值2);
注意:前面的字段名省略的话,等于都写上了!所以值也要都写上!
insert插入日期
str_to_date:将字符串varchar类型转换成date类型。str_to_date('字符串日期', '日期格式')
date_format:将date类型转换成具有一定格式的varchar字符串类型。date_format(日期类型数据, '日期格式')数据库中的date类型会自动转换成varchar类型,date_format没啥用
#格式化数字:2,975
SELECT
ename,
FORMAT(sal, '$999,999') AS sal
FROM
emp;
mysql的日期格式:%Y 年,%m 月,%d 日,%h 时,%i 分,%s 秒
INSERT INTO t_user (id, NAME, birth)
VALUES
(1,
'zhangsan',
STR_TO_DATE('01-10-1990', '%d-%m-%Y')
);
mysql短日期默认格式:%Y-%m-%d
mysql长日期默认格式:%Y-%m-%d %h:%i:%s
修改update(DML)
语法格式:
update 表名 set 字段名1=值1,字段名2=值2... where 条件;
UPDATE
t_user
SET
NAME = 'jack',
birth = '2000-10-11'
WHERE id = 2 ;
#修改id=2的name和birth,没有条件会修改所有的name和birth
删除数据 delete (DML)
语法格式:delete from 表名 where 条件;
注意:没有条件,整张表的数据会全部删除!
insert语句一次插入多条记录
语法:insert into t_user(字段名1,字段名2) values(),(),();
快速删除表中的数据【truncate比较重要】
delete from dept_bak; (delete属于DML语句)
表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放,效率低,支持回滚
truncate table dept_bak; (这种操作属于DDL操作。)
truncate这种删除效率比较高,表被一次截断,物理删除,不支持回滚
删除表操作:drop table 表名;
△约束
包括:
非空约束:not null
唯一性约束: unique
主键约束: primary key (简称PK)
外键约束:foreign key(简称FK)
检查约束:check(mysql不支持,oracle支持)
非空约束not null约束的字段不能为NULL。
唯一性约束: unique
CREATE TABLE t_vip (
id INT,
NAME VARCHAR (255) UNIQUE,
email VARCHAR (255)
) ;
#name字段虽然被unique约束了,但是可以为NULL
name和email两个字段联合起来具有唯一性
CREATE TABLE t_vip (
id INT,
NAME VARCHAR (255),
email VARCHAR (255),
UNIQUE (NAME, email)
);
/*约束没有添加在列的后面,这种约束被称为表级约束
需要给多个字段联合起来添加某一个约束的时候,需要使用表级约束
*/
在mysql当中,如果一个字段同时被not null和unique约束的话,该字段自动变成主键字段。(注意:oracle中不一样!)
主键约束(primary key,简称PK)
主键值是每一行记录的唯一标识。
记住:任何一张表都应该有主键,没有主键,表无效
CREATE TABLE t_vip(
id INT PRIMARY KEY,
NAME VARCHAR (255)
);
在实际开发中不建议使用:复合主键。建议使用单一主键!
主键值存在的意义就是这行记录的身份证号,只要意义达到即可,单一主键可以做到
一张表,主键约束只能添加1个。(主键只能有1个。)
主键值建议使用: int bigint char 等类型。
不建议使用:varchar来做主键。主键值一般都是数字,一般都是定长的!
自然主键:主键值是一个自然数,和业务没关系。
业务主键:主键值和业务紧密关联,例如拿银行卡账号做主键值。
在实际开发中自然主键使用比较多,因为主键只要做到不重复就行,不需要有意义。
外键约束(foreign key,简称FK)
请设计数据库表,来描述“班级和学生”的信息
第一种方案:班级和学生存储在一张表中。特点:数据冗余,空间浪费!
第二种方案:班级一张表、学生一张表
t_class 班级表
classno(pk) classname
100 高三1班
101 高三2班
t_student 学生表
no(PK) name cno(FK引用t_class这张表的classno)
1 jack 100
2 lucy 101
当cno字段没有任何约束的时候,可能会导致数据无效。可能出现一个102,但是102班级不存在。
所以为了保证cno字段中的值都是100和101,需要给cno字段添加外键约束。
那么:cno字段就是外键字段。cno字段中的每一个值都是外键值。
注意:
t_class是父表
t_student是子表
删除表的顺序?
先删子,再删父。
创建表的顺序?
先创建父,再创建子。
删除数据的顺序?
先删子,再删父。
插入数据的顺序?
先插入父,再插入子。
子表中的外键引用的父表中的某个字段,被引用的这个字段不一定是主键,但至少具有unique约束。外键值可以为NULL。
存储引擎
存储引擎是MySQL中特有的一个术语,其它数据库中没有。
实际上存储引擎是一个表存储/组织数据的方式
mysql默认的存储引擎是:InnoDB
mysql默认的字符编码方式是:utf8
#建表时指定存储引擎,以及字符编码方式
CREATE TABLE t_product(
id INT PRIMARY KEY,
NAME VARCHAR(255)
)ENGINE=INNODB DEFAULT CHARSET=gbk;
InnoDB存储引擎:支持事务,支持数据库崩溃后自动恢复机制。非常安全
MEMORY存储引擎:查询效率是最高的。不需要和硬盘交互,不安全,关机之后数据消失,因为数据和索引存在内存中。
△事务(TCL)
一个事务其实就是一个完整的业务逻辑,是一个最小的工作单元、不可再分。本质上,一个事务其实就是多条DML语句同时成功,或者同时失败!
什么是一个完整的业务逻辑:
将A账户的钱减去10000(update语句)
将B账户的钱加上10000(update语句)
这就是一个完整的业务逻辑。
以上的操作是一个最小的工作单元,要么同时成功,要么同时失败,不可再分,这样才能保证钱是正确的。
只有DML语句(insert delete update)才会有事务这一说,其它语句和事务无关!
一旦涉及到数据的增、删、改,那么就一定要考虑安全问题。
在事务的执行过程中,每一条DML的操作都会记录到“事务性活动的日志文件”中。在事务的执行过程中,我们可以提交事务,也可以回滚事务。
提交事务:commit; 语句
清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。
提交事务标志着,事务的结束。并且是一种全部成功的结束。
回滚事务:rollback; 语句(只能回滚到上一次的提交点!)
将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件
回滚事务标志着,事务的结束。并且是一种全部失败的结束。
mysql默认情况下是支持自动提交事务的:每执行一条DML语句,则提交一次。
关闭自动提交机制:start transaction
事务包括4个特性
A:原子性
说明事务是最小的工作单元。不可再分。
C:一致性
所有事务要求,在同一个事务当中,所有操作必须同时成功,或者同时失败
I:隔离性
A事务和B事务之间具有一定的隔离。
教室A和教室B之间有一道墙,这道墙就是隔离性。
D:持久性
事务最终结束的一个保障。事务提交,就相当于将没有保存到硬盘上的数据保存到硬盘上!
事务和事务之间的隔离级别有4个:
读未提交:read uncommitted
事务A可以读取到事务B未提交的数据。存在脏读现象。
读已提交:read committed
事务A只能读取到事务B提交之后的数据。解决了脏读的现象,不可重复读取数据。在事务开启之后,第一次读到的数据是3条,当前事务还没有结束,可能第二次再读取的时候,读到的数据是4条,3不等于4,称为不可重复读取。
可重复读:repeatable read
解决了不可重复读取数据,可读取到的数据都是幻象。不够真实!早晨9点开始开启了事务,只要事务不结束,到晚上9点,读到的数据还是那样!读到的是假象。不够绝对的真实。
序列化/串行化:serializable
这是最高隔离级别,效率最低。解决了所有的问题。不能并发,线程同步(事务同步)
索引(index)
索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。
在任何数据库当中主键上都会自动添加索引对象,另外在mysql当中,一个字段上如果有unique约束的话,也会自动创建索引对象。
在任何数据库当中,任何一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号。
索引是一个单独的对象,不同的存储引擎以不同的形式,不管索引存储在哪里,索引在mysql当中都是一个树的形式存在。(自平衡二叉树:B-Tree)
#创建索引:
create index emp_ename_index on emp(ename);
#给emp表的ename字段添加索引,起名:emp_ename_index
#删除索引:
drop index emp_ename_index on emp;
#将emp表上的emp_ename_index索引对象删除。
视图(view)
view:站在不同的角度去看待同一份数据。
创建视图对象:
create view dept2_view as select * from dept2;
删除视图对象:drop view dept2_view;
注意:只有DQL语句才能以view的形式创建。
视图的特点:通过对视图的操作,会影响到原表数据。
假设有一条非常复杂的SQL语句,而这条SQL语句需要在不同的位置上反复使用。可以把这条复杂的SQL语句以视图对象的形式新建。 在需要编写这条SQL语句的位置直接使用视图对象,可以大大简化开发。并且利于后期的维护,因为修改的时候也只需要修改一个位置就行,只需要修改视图对象所映射的SQL语句。
增删改查,又叫做:CRUD。
C:Create(增),R:Retrive(查:检索)
U:Update(改), D:Delete(删)
DBA常用命令:
△数据的导入和导出(数据的备份)
在windows的dos命令窗口中:
mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123456
/*将bjpowernode导出到D盘*/
#可以导出指定表 emp
mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p123456
#数据导入
#需要先登录到mysql数据库服务器上。
然后创建数据库:create database bjpowernode;
使用数据库:use bjpowernode
然后初始化数据库:source D:\bjpowernode.sql
数据库设计三范式
数据库表的设计依据。教你怎么进行数据库表的设计
第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分。
第二范式:建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,不要产生部分依赖。
第三范式:建立在第二范式的基础之上,要求所有非主键字段直接依赖主键,不要产生传递依赖。
多对多,三张表,关系表两个外键
一对多,两张表,多的表加外键
一对一,外键唯一
MySQL练习题:MySQL练习题_xiaosa的博客-CSDN博客