SQL语言分为:
-
DQL(数据查询语言)
-
DML(数据操作语言)
-
DDL(数据定义语言)
-
DCL(数据控制语言)
DQL数据查询语言
每个sql语句都应该有 “;” 一个sql语句是从from开始的,可以将from看成for循环
大部分数据库都是不区分大小写的
-- 查询整个表
select * from 表名;(不建议这样写,效率低)
--查询属性1 属性2(整列)
select 属性1,属性2 from 表名;
--输出公司的职工工资(comm+sal),oracle内部方法nvl(字段,value):将任何字段为空的值 修改为value
select empno,sal+nvl(comm,0) from emp;
--nvl2(字段,val1,val2) 方法:如果字段是空 返回val2,如果字段不是空,返回val1
select ename,sal(comm,comm,0) from emp; // 如果comm是空,返回0 如果comm不是空 返回comm本身
select empno,ename,job(job,job,'没有职位') from emp;
-- decode 类似于 switch..case...
select ename,decode(job,'CLERK','职员',‘SALESMAN’,‘销售’,‘MANAGER’,'经理') from emp; //输出员工职位 职位是CLERK的输出职员...
--修改字段名(as),起别名
- select empno,sal+nvl(comm,0) as month_sal from emp;
- select empno,sal+nvl(comm,0) month_sal from emp;
- select empno no,empname name from emp
-- 给表定 对象
select e.empno from emp e;(e相当于emp表的一个对象)
--排序(按照年薪排序)(order by 优先级最低,通常状况下写在语句末尾,并且最后执行)
- select empno,ename,((sal)+nvl(comm,0))*15 as year_sal from emp order by year_sal asc;
- (asc 升序 desc 降序)
-- 连接运算符 将各个字段的内容连接到一起
select empno||ename from emp;
-- 查询公司职位,并去除重复的职位,当同时修饰多个字段时,完全重复的才会消除(必须名字和职位都相同才去除)
- select distinct job from emp;
- select distinct job ename from emp;
条件查询语句
在数据库中用于判断值是否相等 用 = ;判断值是否不等, 用 != ;部分数据库不支持 != 通用的不等于:<>
-- 查询出部门编号是10的员工编号 和 姓名
select empno,ename from emp where depno=10;
-- 查询姓名为Smith的员工编号和姓名,oracle下默认字符串是单引号,并且不能使用双引号;但是部分其他数据库可以
--oracle 关键字、字段 都不区分大小写;但是数据值区分大小写
select empno,ename from emp where ename='Smith';
--字符相关的函数:initcap(String):首字母大写
select empno,ename from emp where initcap(ename)='Smith';将ename字段的值转换为大写
--upper(string) 全大写
select empno,ename from emp where upper(ename)='SMITH';
--lower(string) 全小写
select empno,ename from emp where lower(ename)='smith'
--查询入职日期是1981/9/28的员工编号、姓名和入职日期
-- 修改日期格式,可以使用to_char() 函数将 日期转换为字符串,类似于
select empno,ename,hiredata from emp where to_char(hiredata,'yyyy-MM-dd')='1981-09-28'
其他运算符
-- 查询 出工资在 1000 到1500 之间的员工信息 and类似于Java的&&运算符,但是oracle不支持&&,部分其他数据库支持
select * from emp where sal >=1000 and sal<= 1500;
-- 类似于逻辑运算符的关键字: between...and 在...之间
select * from emp where sal between 1000 and 1500;
-- or 在oracle中想要表达满足其中一个条件的情况时,使用or,类似于Java的 ||
select * from emp where sal < 1000 or sal >1500;
-- not between..and...
select * from emp wher sal not between 1000 and 1500;
-- 可以通过in关键字 取一个区间内容,in效率极低,需要优化:工资为1200或者1500或者1600或者2500
select * from emp where sal in(1200,1500,1600,2500);
-- in也可以取in的反区间 not in:工资不为1200或者1500或者1600或者2500
select * from emp where sal not in(1200,1500,1600,2500);
--奖金为空的员工信息
select * from emp where comm is null;
null的特性:
- 任何与null做运算的表达式结果都是null
- 不可以使用 = 或者 != 做条件判断,只能用is或is not 做条件判断
- null排序时为最大,代表正无穷;在部分其他数据库中代表负无穷
- 被多行函数/组函数 忽略
多行函数 组函数
--查询出公司当前员工数 count()
select count(empno) from emp;
-- 查询出公司当前的总工资和 sum()
select sum(sal) from emp;
-- 查询出公司当前的工资水平 avg()
select sum(sal)/count(empno) from emp;
select avg(sal) from emp;
-- 查询出公司最高工资 max()
select max(sal) from emp
-- 查询出最低工资 min()
select min(sal) from emp
-- 查询公司的平均奖金
select sum(comm)/count(empno) from emp;
select avg(nvl(comm,0)) from emp;
--求公司的职位种类
select count(distinct job) from emp;
group by 分组查询
-- 求公司各部门的平均工资
select avg(sal) from emp group by deptno;
--求公司各职位的最高工资、最低工资
select max(sal),min(sal) from emp group by job;
--求公司各职位的工资总和
select sum(sal) from emp group by job;
求公司各部门人数
select deptno,count(empno) from emp group by deptno;
分组条件查询
注意:
- 1. group by 之后不允许进行where操作
- 2.where语句先执行,则在where语句中不可以使用之前的组函数生成的别名
- 3.where 语句后不可以使用分组函数
- 4.having 语句后追加的组函数 不可以使用别名
- 5.having 语句不可以使用之前的组函数生成的别名
- 6.group by 后的条件查询语句 必须使用having进行判断,不能使用where 功能一致,但是原理不同
求平均工资大于2000的部门
select depno,avg(sal) avg_sal from emp group by depno having avg(sal) >2000;
求部门人数大于5的编号和人数
select depno,count(empno) as count from emp group by depno having count(empno)>5;
-- 模糊查询 like,需要匹配相应的通配符
-- 每一个_代表一个字符
-- 名字是Sx的员工信息
select * from emp where name like 'S_';
-- % 代表任意字符:
-- 名字中有s的员工信息
select * from emp where name like '%s%';
-- dual 虚表,在数据库中用于存储基本字符 运算符 基本函数的表 更多的时间用于联系使用
-- 字符函数
-- initcap(char) 首字母大写
-- upper(char) 全部大写
-- lower(char) 全部小写
-- 使用dual显示hello world
- -- select 'world' from dual;
- -- select initcap('world') from dual;
- -- select upper('world') from dual;
- -- select lower('world') from dual;
-- ltrim(char,set) 左裁剪 显示 world
select ltrim('hello world','hello') from dual;
-- rtirm 右裁剪 显示hello
select rtrim('hello world','world') from dual;
-- translate 转换 第一个参数是被修改的字符串 第二个是字符集合 第三个是对应字符集要转换的值
select translate('world','world',‘12345’) 输出12345
--replace 替换 第一个参数是被修改的字符串 第二个是被修改的字符集合 第三个是要修改成为的值
select replace('hello world','hello','你好') 输出你好world
-- instr 查找
select instr(‘hello world’,‘d’)from dual; //输出11
-- substr 子字符串
select substr('hello world',5,11) from dual; //输出 world
-- concat 连接字符串:输出 hello world
select concat('hello','world') from dual;
select 'hello' || 'world' from dual;
数值函数
-- abs(number) 绝对值
-- floor(number) 向下取整
--round(number) 四舍五入
-- ceil(number) 向上取整
-- sin(number) 正弦 cos(number) 余弦 tan(number) 正切
-- power(number,n) number的n次方
-- sqrt(number) 开方
-- mod(number,n) 求余数
-- sign(number) 求符号
-- trunc(number,n) 截断
select trunc(10.99999999,2) from dual; 显示10.99
日期函数 to_char() to_date()
- to_date 如果将一个字符串转换为date类型,则必须说明转换格式 否则语法错误
- 如果是一个date类型,继续使用to_date 会将date默认转换为与sysdate同种类型的date
-- 返回当前日期
select sysdate from dual;
select to_char(sysdate,'yyyy-MM--dd hh:mi:ss') from dual;
select to_date('1992-02-18','yyyy-mm-dd') from dual;(将一个字符串转换为data类型)
-- 查询当前公司员工的编号和工作年限
select empno,ename,ceil(sysdate - to_date(hiredate))/365) work_year from emp;
select empno,ename,ceil((sysdate-hiredate)/365) work_year from emp;
-- 返回两个日期相隔的月数
select months_between(sysdate,hiredate) workyear from emp;
-- 返回 把月份数 添加到指定日期上
select add_months(sysdate,1) from emp; //系统当前日期加上一个月
-- next_day 返回指定日期对应后的新的日期
select next_day(sysdate,'星期一') from dual; //显示当前日期的之后的第一个星期一的日期
-- last_day 返回指定日期所在月的最后一天的日期
select last_day(sysdate) from dual;
-- round 指定日期,按照某种方式进行四舍五入
select round(sysdate,'year') from dual;
-- trunc 按照某种方式 进行截断日期
select trunc(to_date('2017-05-25 11:59:59' , 'yyyy-mm-dd hh24:mi:si') , 'day') from dual; 只显示 2017/05/21
--查询出各职位的最高工资 列出2000以上的并按照从多到少的顺序排序 并排除没有职位的情况
select job,max(sal) as max_sal from emp where job is not null group by job having max(sal) >2000 order by max_sal desc;
SQL语句的执行顺序:
- 1.执行from语句
- 2.执行where 语句
- 3.执行group by 语句
- 4.执行having语句
- 5.执行select
- 6 执行order by
DML(数据操作语言)
数据库的本质是文件管理系统 ——增、删、改、查的实现
-- insert into语句
常见的插入方式有两种:
1.普通插入:insert into emp(1002,'Mike','经理',1001,to_date('2008-09-29','yyyy-mmm-dd',20000,4000,null);
2.对应插入:insert into emp(empno,ename) values(1003,'Sonia');
--复制表内容并再插入到原表
insert into emp select * from emp;
-- 复制A表内容再插入到B表中 注:复制表的数据时 不可以添加as关键字
insert into B select * from A;
--复制一个表的所有内容 到一个新表中 注:复制表时 必须添加as关键字 此处不可略
create table emp_test as select * from emp;
-- 删除 delete from
--删除整个表
delete from emp;
--清空表 有更快的方式,而且没有回滚撤销
truncate table emp;
--条件删除语句
delete from emp where empno=0;
-- 删除所有工资是空的员工
delete from emp where sal is null;
--删除名字中带有L的员工
delete from emp where ename like '&L%';
-- 修改 update
--所有人修改名为 a
update emp set ename='a';
--修改表内多列数据
update emp set ename = 'a' , job = 'xicesuo',sal = 1000;
--条件修改语句
update emp set ename = 'zz' where comm = 0;
--修改所有工资小于2000的员工 将当前工资提高500 奖金设置为 2000
update emp set sal = sal+500,comm=2000 where sal<2000;
子查询语句
-- 查询谁比琼斯的工资高
select ename,sal from emp where sal > (select sal from emp where ename = 'JONES')
-- 查询职务和SCOTT相同,比SCOTT雇佣时间早的员工信息
select * from emp where job = (select job from emp where ename = 'SCOTT') and hiredate < (select hirdate from emp where ename = 'SCOTT')
-- 查询工资比SCOTT 高 或者雇佣比他早的雇员编号和名字
select empno,ename from emp where sal > (select sal from emp where ename = 'SCOTT') or hiredate < (select hirdate from emp where ename = 'SCOTT')
-- 如果存在多个SCOTT ???
-- 多行子查询 any all
select * from emp where sal > all (select sal from emp where ename = 'SCOTT') ; 比所有SCOTT 工资都高
select * from emp where sal > any(select sal from emp where ename = 'SCOTT')
-- 查询职务和其中一个SCOTT 相同 比所有SCOTT 雇佣时间早的员工信息
select * from emp where job = any(select job from emp where ename = 'SCOTT') and hiredata < all(select hiredata from emp where ename = 'SCOTT')
关联子查询 当子查询的值依赖于主查询的值 必须使用关联子查询
-- 查询出比自身部门的平均工资高的姓名、编号和工资
select ename,empno,sal from emp e1 where sal > (select avg(sal) from emp e2 where e1.deptno = e2.deptno)
-- 查询出 各职业最高工资的员工编号 姓名
select empno,ename from emp e1 where sal = (select max(sal) from emp e2 where e1.job = e2.job);
--exists 关键字
- -- exists 使用在where语句之后,不添加任何列名,直接追加子查询
- -- exists 关键字不在乎某一列的数据,只在乎该数据是否存在于子查询中,存在返回真,不存在返回假;所以where与exists之间不需要列名,又由于主查询没有选择列名 那么子查询也不需要返回一个列的数据,通常情况下 exists的子查询就写成select 1
- -- select 1 查询一个常量,节省内存,减少内存占用量
-- 查询部门 20 中职务同部门10的雇员 一样的员工信息
select * from emp where deptno = 20 and job in (select job from emp where deptno = 10);
select * from emp e1 where deptno = 20 and exists (select 1 from emp e2 where deptno=10 and e1.job = e2.job )
多表关联查询
92版(只支持Oracle) 99版(通用)
-- 92版多表查询
--等值连接
-- 查询员工的姓名、编号、工作地点
select empno,ename,loc from emp,dept where emp.deptno = dept.deptno;
--查询员工的编号、姓名、工作地点和部门编号
select e.empno , e.ename , d.deptno , d.loc from emp e , dept d where e.deptno = d.deptno;
-- 非等值连接
-- 查询员工的工资等级
select empno,ename,sal,grade from emp,salgrade where sal >= losal and sal <=hisal;
select empno,ename,sal,grade from emp,salgrade where sal between losal and hisal ;
-- 外连接
- 1.左外连接
- 2.右外连接
- 3.全外连接(92版没有全外连接)
-- 查询所有员工的编号、姓名和工作地点 把没有部门的员工也显示出来
-- 等值连接无法显示 值为空的数据
select empno,ename,loc from emp,dept where emp.deptno = dept.deptno; // 显示不出来 没有部门的员工
1.左外连接 以等号为分隔符,左外连接写在 右侧参数的后面
select empno,ename,loc from emp e,dept d where e.deptno = d.deptno(+);
2.右外连接 以等号为分隔符,右外连接写在 左侧参数的后面
select empno,ename,loc from emp e , dept d where e.deptno(+) = d.depno;
-- 查询所有员工的编号、姓名和工作地点 把没有员工的部门也显示出来
1.左外连接
select empno,ename,loc from emp,dept where dept.deptno = emp.deptno(+);
2.右外连接
select empno,ename,loc from emp e , dept d where e.deptno(+) = d.depno;
-- 99版多表关联查询
-- 交叉连接 结果是笛卡儿积
select * from emp cross join dept;
-- 自然连接 natural join 类似于等值连接
select * from emp natural join dept;
-- using 语句 表示使用deptno作为等值连接的判断依据
select * from emp join dept using(deptno);
-- on语句 可是是等值的 也可以是不等值的
select * from emp join dept on emp.deptno = dept.deptno;
-- 查询出公司的所有员工编号、姓名、工资、工作地点、工资等级
select empno,ename,sal,loc,salgrade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal ;
-- 外连接
1.左外连接
2.右外连接
3.全外连接
-- 查询出所有员工的信息,没有部门的员工信息也显示出来
1.左外连接 以join为分割线,可以在join前添加关键字 left/right left表示join左侧的表的数据全部显示 right表示右侧表的所有数据都显示
select * from emp left join dept on emp.deptno = dept.deptno;
2.右外连接 显示的是没有员工的部门
select * from emp right join dept on emp.deptno = dept.deptno;
3.全外连接 full join表示 获取两个表内的所有数据
select * from emp full join dept on emp.deptno = dept.deptno;
--自连接
-- 查询出 员工编号和姓名 与 其上司的员工编号、姓名
select e1.empno , e1.ename , e2.empno , e2.ename from emp e1 join emp e2 on e1.mgr = e2.empno;
--- 视图
select * from (select empno.ename from emp) e;
-- 给scott用户授权,可以创建视图
grant create view to scott;
-- 创建一个视图
create or replace view emp_view as (select empno,ename from emp) with read only;
-- 查看视图
select * from emp_view;
--如果一个视图设置为了只读,则不可以进行DML操作,通常情况下视图都是只读的
-- 如果一定要删除,则可以删除整个视图
drop view emp_view;
--同理于table 也可以删除
drop table emp;
-- 视图更多使用在 SQL 语句中,实现复杂的功能
-- 将员工工资改为所在部门平均工资+1000
update emp e1 set e1.sal = (select avg(sal) from emp e2 where e1.deptno = e2.deptno) + 1000;
-- 删除重复部门,只留下一项
-- 思路:1.按照部门名称分组,求数量大于1的 表示该部门存在重复
2.获取重复部门名称
3.查找所有与该名称重复的数据
4.删除 除去最小编号的其他 与重复部门名称相同的 数据
视图不可以做DML操作
delete from dept where deptno != (select min(deptno) min_no from dept where dname in (select dname from (select dname,count(*) count_name from dept group by dname) d where count_name>1) group by dname) and dname =(select dname from (select dname,count(*) count_name from dept group by dname) where count_name > 1)
-- 更新员工工资为他的主管的工资、奖金
--思路:1.查询出每个员工对应主管的工资
2.更新所有员工的工资
3.查询出每个员工对应主管的奖金
4.更新所有员工的奖金
update emp e set sal = (select sal from (select distinct e1.empno,e1.ename,e1.sal,e1.comm from emp e1 join emp e2 on e1.empno = e2.mgr) where e.mgr = empno), comm = (select comm from (select distinct e1.empno,e1.ename,e1.sal,e1.comm from emp e1 join emp e2 on e1.empno = e2.mgr) where e.mgr = empno) where e.mgr is not null;
oracle基本数据类型
字符串类
- 1)char 定长字符串 默认长度是1
- 2)varchar2 变长字符串 必须提供最大长度
数值类 Number
- 1)number 可以是整数,也可以是浮点数
日期类型
- 1)date 日期格式,可以显示yyyy-mm-dd hh:mis:ss 格式的日期类型
- 2)timestamp 格式同上,但是可以包含小数点位的秒 最多包含9位小数
创建数据库表
create table 表名(列名 类型,列名1 类型1......)
--建立一张用来存储学生信息的表
create table student(
sno number,
sname varchar2(20),
sex char,
age number,
enterdate date,
classno number,
email varchar2(50)
math number(4,1), 一共四位,一位是小数
english number(3,1)
);
--删除一张表 包括表本身都被删除
drop table student;
-- 修改表
-- alter table 表名 action
--添加列
alter table student add sex char(1);
--修改列
alter table student modify (sex varchar(20));
--删除列
alter table student drop column sex;
-- 修改列名
alter table student rename column sname to name;
--约束
--常用约束:
- 1.主键 primary key 表示非空且唯一,并追加一个索引,提高查询效率,降低插入效率
- 2.非空 not null
- 3.唯一 unique
- 4.检查 check
- 5.外键 foreign key 表示关联一个父列 如果该列没有值 则不允许插入 如果本身存有父列的值 则父列不允许删除
-- 存有约束的student表
create table student(
sno number unique not null,
sname varchar2(20) not null,
pwd varchar2(100) not null,
score number(4,1) check(score <= 100 and score >=0)
);
-- 删除约束
alter table 表名 drop constraints 约束名;
--学生表 编号、姓名、分数、班级编号
--班级表 编号、教室、辅导员名、教师名
create table student(
sno number primary key,
sname varchar2(20),
score number,
clazzno number ,
foreign key(clazzno) references clazz(clazzno)
);
create table clazz(
clazzno number primary key,
clazzroom number,
assistant varchar2(20),
tname varchar2(20)
)
-- constraints 的特点::
- 提高数据库的安全性,降低数据的错误率
- 降低添加、删除、修改效率 如果是一个添加删除修改频率比较频繁的数据库,尽量不要添加过多的约束
- 通常情况下,只添加主键和外键约束
约束的添加方式有三种:
- 1.在建表语句时,直接在列名之后
- 2.在建表语句的末尾,添加constraints关键字, 约束名 列名 约束关键字
- 3.创建完毕表后,使用alter table 表名 constraints 关键字 约束名 约束关键字(列名)
- 通常情况下使用2,3两种方式 添加约束,方便删除和修改
第二种方式:
create table t_student(
sno number,
sname varchar2(20) not null,
score number(4,1),
constraints PK_SNO primary key(sno),
constraints NOTNULL_SNAME not null(sname),
constraints CHECK_SCORE check(score<=100 and score >= 0)
);
第三种方式:
-- 添加主键约束
alter table t_student add constraints PK_SNO primary key(sno);
--添加检查约束
alter table t_student add constraints CHECK_SCORE check(score<=100 and scor >= 0);
-- 删除主键约束
alter table t_student drop contraints PK_SNO;
--删除检查约束
alter table t_student drop constraints CHECK_SCORE;
-- DML操作数据库用户
--创建一个用户
create user bjsxt identified by bjsxt;
-- 给一个用户授权
-- 常见用户权限:
- connect 临时用户
- resource 普通用户
- dba管理员用户
grant connect,resource to bjsxt;
--取消一个用户的权限
revoke resource from bjsxt;
--删除一个用户
drop user bjsxt;
序列
-- 需要插入学生数据,但是需要学生编号是自动生成的
-- 创建一个序列
create sequence stu_seq;
-- 删除一个序列
drop sequence stu_seq;
-- 插入数据时 使用stu_seq进行插入 stu_seq.nextval
insert into student values (stu_seq.nextval,'a',10,10);
-- 可以在创建序列时,提供参数
create sequence stu_seq1 start with 10000 increment by 1 nocache; (nocache表示没有缓存区)
--使用stu_seq1插入数据
insert into student values (stu_seq1.nextval,'b',10,10);
--事务 TCL语句
在不同的使用环境下会存在自动保存数据 或者 自动撤销数据 的情况
实际上是事务的保存或撤销
- pl/sql 按照自动保存机制
- sqlplus 按照自动撤销机制
- java 按照自动保存机制
- 也可以手动保存或撤销
-- 保存
commit;
--撤销
rollback;
-- 自动保存
set autocommit on;
-- index索引
- 为了提供查询效率而存在于数据表中的 类似目录的内容 叫做索引
- 最常见的索引叫做主键索引 主键约束即是约束 也是索引
- 索引可以提高 > >= = < <= <> in between ..and 关键字的查询效率
- 当数据量提高时,会降低插入、删除、修改的效率
-- 创建一个索引
create index stu_name_index on student(sname desc);
create index stu_score_index on student(score desc);
-- 索引不需要手动使用 在使用查询语句时 自动触发
select score from student;
-- 删除索引
drop index stu_name_index;
drop index stu_score_index;
-- 分页ROWID ROWNUM
-- 使用rowid rownum 时,不推荐使用* ,在部分数据库中报错
-- rowid 指的是在硬盘空间地址 在存储数据后自动生成,可以作为条件查询数据
-- rownum代表每一行数据对应的行号 rownum不可以使用> 也不可以使用between..and 也不可以使用= 只能使用<比较数据
-- 显示公司工资前五名的员工心思
select * from (select emp.* from emp order by sal desc) where rownum < 6;
-- 显示公司工资第7名到第10名的员工心思
select * from (select rownum r,e.* from (select emp.* from emp order by sal desc) e) where r between 7 and 10;
三大范式
第一范式:数据库中每一列都具有原子性,不可分割
第二范式:属性完全依赖于主键 ( 多对多 )
第三范式:数据库中每一列都和主键之间相关 不能间接相关 (一对多 多对一)
◆ 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。
考虑这样一个表:【联系人】(姓名,性别,电话)
如果在实际场景中,一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF。要符合 1NF 我们只需把列(电话)拆分,即:【联系人】(姓名,性别,家庭电话,公司电话)。1NF 很好辨别,但是 2NF 和 3NF 就容易搞混淆。
◆ 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
考虑一个订单明细表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。
因为我们知道在一个订单中可以订购多种产品,所以单单一个 OrderID 是不足以成为主键的,主键应该是(OrderID,ProductID)。显而易见 Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF 的设计容易产生冗余数据。
可以把【OrderDetail】表拆分为【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)来消除原订单表中UnitPrice,ProductName多次重复的情况。
◆ 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
考虑一个订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID)。
其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主键列都完全依赖于主键(OrderID),所以符合 2NF。不过问题是 CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。
通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。
第二范式(2NF)和第三范式(3NF)的概念很容易混淆,区分它们的关键点在于,2NF:非主键列是否完全依赖于主键,还是依赖于主键的一部分;3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。
---------------------------------------------------mysql-------------------------------------
mysql 与Oracle 不同:
没有默认自带的orcl数据库
必须需要手动创建数据库 或使用 官方推荐的test数据库
选择数据库或者创建数据库
--登陆数据库
mysql -u root -p
--选择数据库
use 数据库名;
--创建数据库
create database sxt201;
--显示数据库
show database;
--删除数据库
drop database 数据库名
-- MySQL 与 Oracle 中dql 基本一致
select * from 表名;
-- dml基本一致
insert into 表名 values(值);
delete from 表名 where 列= 值;
update 表名 set 列名= 列值 where 列 = 值;
-- mysql中基本数据类型 与 oracle 不同
没有number类型,只有int double float
没有varchar2类型 使用 char和varchar
时间类型 使用date(yyyy-mm-dd)datetime(yyyy-mm-dd hh:mm:ss) timestamp(yyyymmddhhmmss)
-- mysql中可以将from dual省略
所以最简单的hello world
select 'hello world'
-- 事务与oracle不同
每一次事务的开始 都需要begin
之后再执行commit和rollback
-- mysql常用引擎 ?
-- mysql不支持全外连接 多表关联查询时 无法全外连接
如果一定要实现,则需要union关键字
oracle中:select * from emp e full join dept d on e.deptno = d.deptno;
mysql中:select * from emp e left join dept d on e.deptno = d.deptno union select * from emp e right join dept d on e.deptno = d.deptno;
-- mysql 不支持序列 如果要自增长 则需要使用一个约束 并且必须是主键约束的条件下auto_increment
alter table student add constraints stu_pk primary key(no) auto_increment;
--建表时添加
create table user (no int primary key auto_increment,name varchar(20));
-- mysql 不支持rowid 和rownum 无法像oracle实现分页
-- 需要使用limit关键字,添加两个参数:1.起始行的坐标 从0 开始 2.显示几条
-- 显示前五条数据
select * from student limit 0,5;
-- 显示5到10条数据
select * from student limit 5,5;
--日期函数有较大区别
select now(); -- 代表当前时间 yyyy-mm-dd hh:mm:ss
select curdate(); -- 代表当前日期 yyyy-mm-dd
select curtime(); -- 代表当前时间 hh:mm:ss
-- mysql可以使用help contents 查询帮助文档内容 所有说明和例子都在其中
--