数据库基础知识

数据库范式

第一范式(1NF)

属性不可分

即数据库表的每一列都是不可分割的基本数据项

说明:在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。

第二范式(2NF)

不存在组合关键字的某些字段决定非关键字段(组合关键字不可拆)

属性完全依赖于主键 (消除部分子函数依赖)

例:假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分),关键字为组合关键字(学号, 课程名称),存在如下决定关系:

(学号, 课程名称) → (姓名, 年龄, 成绩, 学分)

这个数据库表不满足第二范式,因为存在如下决定关系:

(课程名称) → (学分)

(学号) → (姓名, 年龄)

即存在组合关键字中的字段决定非关键字的情况。

正确建表:

学生:Student(学号, 姓名, 年龄);

课程:Course(课程名称, 学分);

选课关系:SelectCourse(学号, 课程名称, 成绩)。

这样的数据库表是符合第二范式的, 消除了数据冗余、更新异常、插入异常和删除异常。

第三范式(3NF)

属性不依赖于其它非主属性(消除传递依赖)

例:假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),关键字为单一关键字"学号",存在如下决定关系:

(学号) → (姓名, 年龄, 所在学院, 学院地点, 学院电话)

这个数据库是符合2NF的,但是不符合3NF,因为存在如下决定关系:

(学号) → (所在学院) → (学院地点, 学院电话)

即存在非关键字段"学院地点"、"学院电话"对关键字段"学号"的传递函数依赖。

正确建表:

学生:(学号, 姓名, 年龄, 所在学院);

学院:(学院, 地点, 电话)。

BCNF

不存在关键字段决定关键字段

例:假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:

(仓库ID, 存储物品ID) →(管理员ID, 数量)

(管理员ID, 存储物品ID) → (仓库ID, 数量)

所以,(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:

(仓库ID) → (管理员ID)

(管理员ID) → (仓库ID)

即存在关键字段决定关键字段的情况,所以其不符合BCNF范式。

正确建表:

仓库管理:StorehouseManage(仓库ID, 管理员ID);

仓库:Storehouse(仓库ID, 存储物品ID, 数量)。

数据库基础

基本操作

建表

#创建表:create table 表名(列名 数据类型 约束,列名 数据类型 约束);
#建表约束:
#主键:primary key 每个表中只能有一列是主键,数据唯一不能重复,不能为空。
#唯一:unique数据不能重复,可以为空,每个表中可以有多列是唯一列
#默认值:default
#非空:not null
#自增:auto_increment
#外键约束:foreign key

创建一个简单的学生表:

create table studentInfo (
    number int primary key auto_increment,
    name varchar(45) unique not null,
    sex enum('男', '女'),
    age int default 18
);

#char(45): 字符串长度是45,长度固定,例如存“hello”,实际存"hel1o889998889...",长度固定占45
#varchar(45): 字符串最大长度是45,例如存“hello”,实际存"hello",实际存多少就占多少长度,不能超过45,一个字符占一个字节,最多存8千个字符
#nvarchar(45): 字符串最大长度是45,例如存“hello”,实际存"hello",实际存多少就占多少长度,不能超过45。使用宽字符集,一个字符占两个字节,数据库最多存8千个字节,就是最多存4千个字符

插入

insert into 表名 values(...);
insert into 表名(...) values(...);

修改

#修改表:alter table 表名...
#1.增加列:alter table 表名 add column 列名 数据类型 约束;
alter table studentinfo add column school int;

#2.修改列的属性:alter table 表名 modify 列名 数据类型 约束;
alter table studentinfo modify school varchar(100);

#3.删除列:alter table 表名 drop 列名;
alter table studentinfo drop school;

#删除表:drop table 表名
drop table studentinfo;

#更新数据:update 表名 set 列名=新的值 where 条件;
update studentinfo set age=19;

update studentinfo set age=20 where name = '小明';

#删除数据:delete from 表名 where 条件;
delete from studentinfo where sex='女';

查询

#查询数据库:select 列名 from 行名;

#模糊查询:where 列名 like 模糊表达式;
#%:匹配任意0到n个字符,例如“小%”,可以查询小王,小青蛙。。。
#_:匹配任意一个字符,例如“张_”,可以匹配张三,张四。。。
select * from studentinfo where name like "%小%";
select * from studentinfo where sex like "%_";
select * from studentinfo;
select * from studentinfo where sex is not null;

#分页查询:limit a,b;(a是起始位置,b是偏移量,也就是多少行) (第几页-1)* 每一页显示几行
select * from studentinfo limit 4,2;
 
#聚合函数
#count():查询个数
select count(*) from studentinfo;
select count(name) from studentinfo;
select count(sex) from studentinfo;

#sum():求和
select sum(score) from sc;
select sum(score) from sc where C='01';
select sum(score) from sc where C='02';

#max():最大值
select max(score) from sc where C='01';

#min():最小值
select min(score) from sc where C='02';

#avg():平均值
select avg(score) from sc where C='01';

#分组:group by 分组条件;
#每门课程的总成绩
select C,sum(score) from sc group by C;

#每个学生的总成绩
select S,sum(score) from sc group by S;

#查询总成绩超过200分的学号和总成绩
select S,sum(score) from sc group by S having sum(score)>=200;

#条件: where 条件规则;
#相等:列名 = 条件;
#大于、小于、大于等于、小于等于:列名 > 条件;列名 < 条件;列名 = 条件,列名 <= 条件;
#不相等:列名 != 条件;只有MYSQL支持 其他: 列名<>值;
#或者: 条件1 or 条件2;
#并且: 条件1 and 条件2;
#介于两者之间: between 条件1 and 条件2;
#在范围内: in (范围);
#不在范围内: not in (范围);

#条件where和having
#当作为条件的列是表中原来就有的,用where加
#当作为条件的列是表中原来没有的,用having加

 多表联查:

#多表联查:
#1、内联: 表1 inner join  2 on 连接条件 inner join 表3 on 连接条件);
select * from student inner join sc on sc.S = student.S;
#2、左联:表1 left ioin 表2 on 连接条件;
select * from student left join sc on sc.S = student.S;
#3、右联:表1 right join 表2 on 连接条件;
select * from student right join sc on sc.S = student.S;
#4、笛卡尔积:select 表1,表2 where 连接条件;
select * from student, sc where sc.S = student.S;

#区别:
#内联: 查询结果取两个表的交集,不包含空的结果
#左联:查询结果以左边表为基准,匹配行,如果没有就显示空
#右联:查询结果以右边表为基准,匹配行,如果没有就显示空
#笛卡尔积:查询结果和内联一致,但是查询效率低,不推荐使用

视图

#视图:view
#视图是为了简化复杂的sql语句提出的概念。视图是一个表或者多个表导出的虚拟表,不是真实存在的,不需要满足范式的要求。
#视图创建好以后长久保留在数据库库中,可以通过视图名使用,跟查询表一样使用。
#创建视图:create view 视图名 as (sql语句);
create view myview as(
select student.*,C,score from student inner join sc on sc.s=student.s
);

函数

#创建函数的语法
#delimiter //  #声明//为新的结束标志 
#create function 函数名(变量名 类型,变量名 类型)
#returns 返回值类型 
#begin
#函数语句;
#函数语句;
#end //
#delimiter ;  #重新声明;为结束标志

#int add(int a,int b)
#{
#    int c=0;
#    c=a+b;
#    return c;
#}

#例子:加法函数
drop function if exists myadd;
delimiter //
create function myadd(a int,b int)
returns int
begin 
	declare c int default 0;
    set c = a + b;
    return c;
end //
delimiter ;
    
#调用函数:select 函数名(参数列表);
select myadd(3,5);

#删除函数:drop function 函数名;
drop function myadd;

#判断是否存在再删除:drop function if exists 函数名;
drop function if exists myadd;

全局变量、局部变量

#局部变量:
#会话变量:@变量名 
set @a = 100;
select @a;

#系统变量(全局变量):
show global variables;
select @@basedir;

 if 语法

#if语法:
#if 表达式1 then 执行语句;执行语句;执行语句;
#elseif 表达式2 then 执行语句;执行语句;执行语句;
#else 执行语句;
#end if;

#例子:判断输入的值是正数、负数和零 
drop function if exists myfun;
delimiter //
create function myfun(a int)
returns varchar(100)
begin
	declare res varchar(100) default '';
    if a>0 then set res='正数';
    elseif a<0 then set res='负数';
    else set res='零';
    end if;
    return res;
end //
delimiter ;
select myfun(-10);

case 语法

#case:
#case 变量 when 值1 then 执行语句;
#          when 值2 then 执行语句;
#          when 值3 then 执行语句;
#end case;
drop function if exists myfun;
delimiter //
create function myfun(a int)
returns varchar(100)
begin
	declare res varchar(100) default '';
	case a when 10 then set res='十';
		   when 0 then set res='零';
           when -10 then set res='负十';
    end case;
    return res;
end //
delimiter ;
select myfun(0);

#case when 表达式1 then 执行语句;
#     when 表达式2 then 执行语句;
#     when 表达式3 then 执行语句;
#end case;
drop function if exists myfun;
delimiter //
create function myfun(a int)
returns varchar(100)
begin
	declare res varchar(100) default '';
	case when (a=0) then set res='零';
		 when (a>0) then set res='正数';
		 when (a<0) then set res='负数';
    end case;
    return res;
end //
delimiter ;
select myfun(10);

 循环

#1、while循环
#while 循环条件
#do
#执行语句;
#end while;

#例子:累加,计算1+2+...+n
drop function if exists mysum;
delimiter //
create function mysum(n int)
returns int
begin
	declare nSum int default 0;
	declare i int default 1;
	while i <= n
    do
		set nSum = nSum + i;
		set i = i + 1;
	end while;
	return nSum;
end //
delimiter ;
select mysum(100);

#2、其他循环: mysql没有for循环,有repeat和loop循环

存储过程

#存储过程:procedure,大型数据库中一组为了完成特定功能的sql语句的集合。存储在数据库中,一次编译永久有效。
#优点:
#1、减少网络流量
#2、增强代码的重用性和共享性
#3、加快系统运行速度
#4、使用灵活

#创建存储过程语法:
#delimiter //
#create procedure 过程名(变量名 类型,变量名 类型)
#begin
#sql语句;
#sql语句;
#end //
#delimiter ;
#存储过程没有返回值,但是可以通过定义参数的类型,IN|OUT|INOUT三种参数类型,不定义默认是输入类型参数。

#调用存储过程: ca11 存储过程名(参数列表);
#删除: drop procedure 过程名;
#drop procedure if exists 过程名:

#函数和存储过程的区别:
#1、函数中不能写sql语句,存储过程中可以写sql语句,存储过程中可以调用函数。
#2、函数有返回值,存储过程没有返回值,但是可以声明参数为OUT|INOUT类型来返回数据。

#写一个分页的存储过程。参数:当前是第几页(nPage int),每页显示多少行(nCount int),查询哪个表(tableName varchar(20))。
#要求做参数校验:如果页数小于等于0,就显示第一页数据;如果页数超过最大页数,就显示最后一页的数据。
#先写固定查student表
#再写拼表名
drop procedure if exists limitpro;
delimiter //
create procedure limitpro(nPage int, nCount int)
begin
	declare nOffset int default 0;
    declare nMaxPage int default 0;
    declare nSumCount int default 0;
    #查询数据行数
    select count(*) into nSumCount from student;
    #计算最大页数
    set nMaxPage = ceil(nSumCount / nCount);
    #判断页数合法性
    if (nPage <= 0) then set nPage = 1;
    end if;
    if (nPage > nMaxPage) then set nPage = nMaxPage;
    end if;
    
    set nOffset=(nPage-1)*nCount;
    select * from student limit nOffset,nCount;
end //
delimiter ;
call limitpro(2,6);

触发器

#创建触发器语法:
#delimiter //
#create trigger 触发器名 #触发器没有参数,也没有返回值
#after/before 操作       #在。。。操作之前或者之后
#on 表名				 #产生触发的表(对哪个表进行操作)
#for each row			 #影响每一行
#begin
#sql语句;
#end //
#delimiter ;

#例子: 删除student表的时候,同时删除sc表中这个同学的选课信息
delimiter //
create trigger mydel
after delete
on student
for each row
begin
	#同时删除sc表中这个同学的选课信息
    delete from sc where S = old.S;
    #old表: 删除的数据或者修改之前的数据
    #new表: 新增加的数据或者修改之后的数据
end //
delimiter ;
delete from student where s = '01';

#增加
delimiter //
create trigger myinsert
after insert
on student
for each row
begin
	#同时帮这个同学自动选择01课程
    insert into sc(S,C) values (new.S,'01'); 
end //
delimiter ;
insert into student(S,Sname,Ssex) values (1,'李雪','女'); 

#修改数据例子:修改学号的时候,同时修改sc表中的学号
delimiter //
create trigger myupdate
after update
on student
for each row
begin
	#同时修改sc表中的学号
    update sc set S=new.S where S=old.S;
end //
delimiter ;
update student set s='20' where s='1';

事务

#事务:作为单个逻辑单元执行的一系列sql语句的集合,操作要么都执行,要么都不执行。
#4个特性:ACID
#原子性:事务是最小的工作单元,不可再分,要么都执行,要么都不执行。
#一致性:数据库的完整性约束不能被破坏。
#隔离性:并行执行的多个事务,多个事务互相不影响。
#持久性:事务数据提交以后,持久的保存在数据库中。

#语法: transaction
#开启事务: start transaction;
#一系列sql语句;
#提交: commit;
#回滚: rollback;
start transaction;
update bank set money = money + 50 where name ='小李';
update bank set money = money - 50 where name ='小赵';
select * from bank;
commit;

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值