数据约束

数据约束

什么数据约束 : 对用户操作表的数据进行约束

  1. 默认值
  • 作用: 当用户对使用默认值的字段不插入值的时候,就使用默认值。
  • 注意:
    1)对默认值字段插入null是可以的。
    2)对默认值字段可以插入非null
CREATE TABLE student(
    id INT,
    NAME VARCHAR(20),
    address VARCHAR(20) DEFAULT '广州天河'  -- 默认值
)
DROP TABLE student;
-- 当字段没有插入值的时候,mysql自动给该字段分配默认值
INSERT INTO student(id,NAME) VALUES(1,'张三');
-- 注意:默认值的字段允许为null
INSERT INTO student(id,NAME,address) VALUE(2,'李四',NULL);
INSERT INTO student(id,NAME,address) VALUE(3,'王五','广州番禺');
  1. 非空
  • 作用: 限制字段必须赋值
  • 注意:
    1)非空字符必须赋值
    2)非空字符不能赋null
-- 需求: gender字段必须有值(不为null)
CREATE TABLE student(
    id INT,
    NAME VARCHAR(20),
    gender VARCHAR(2) NOT NULL -- 非空
)
-- 非空字段必须赋值
INSERT INTO student(id,NAME) VALUES(1,'李四');
-- 非空字符不能插入null
INSERT INTO student(id,NAME,gender) VALUES(1,'李四',NULL);
  1. 唯一
  • 作用: 对字段的值不能重复
  • 注意:
    1)唯一字段可以插入null
    2)唯一字段可以插入多个null
CREATE TABLE student(
    id INT UNIQUE, -- 唯一
    NAME VARCHAR(20)
)
INSERT INTO student(id,NAME) VALUES(1,'zs');
INSERT INTO student(id,NAME) VALUES(1,'lisi'); -- ERROR 1062 (23000): Duplicate entry '1' for key 'id'  
INSERT INTO student(id,NAME) VALUES(2,'lisi');
  1. 主键
  • 作用: 非空+唯一
  • 注意:
    1)通常情况下, 每张表都会设置一个主键字段; 用于标记表中的每条记录的唯一性
    2)建议不要选择表的包含业务含义的字段作为主键,建议给每张表独立设计一个非业务含义的id字段
DROP TABLE student;
CREATE TABLE student(
    id INT PRIMARY KEY, -- 主键
    NAME VARCHAR(20)
)
INSERT INTO student(id,NAME) VALUES(1,'张三');
INSERT INTO student(id,NAME) VALUES(2,'张三');
-- INSERT INTO student(id,NAME) VALUES(1,'李四'); -- 违反唯一约束: Duplicate entry '1' for key 'PRIMARY'
-- insert into student(name) value('李四'); -- 违反非空约束: ERROR 1048 (23000): Column 'id' cannot be null
  1. 自增长 : 自动递增
CREATE TABLE student(
    id INT(4) ZEROFILL PRIMARY KEY AUTO_INCREMENT, -- 自增长,从0开始  ZEROFILL 零填充
    NAME VARCHAR(20)
)
-- 自增长字段可以不赋值,自动递增
INSERT INTO student(NAME) VALUES('张三');
INSERT INTO student(NAME) VALUES('李四');
INSERT INTO student(NAME) VALUES('王五');
SELECT * FROM student;
-- 不能影响自增长约束
DELETE FROM student;
-- 可以影响自增长约束
TRUNCATE TABLE student;
  1. 外键 : 约束两种表的数据
  • 若果出现两种表的情况:
    1> 解决数据冗余高问题 -> 独立出一张表; 例如 : 员工表和部门表
    2> 使用外键约束:约束插入员工表的部门ID字段值
    • 问题出现:在插入员工表数据的时候,员工表的部门ID字段可以随便插入!
    • 解决办法: 在员工表的部门ID字段添加一个外键约束
-- 部门表(主表)
CREATE TABLE dept(
    id INT PRIMARY KEY,
    deptName VARCHAR(20)
)
-- 修改员工表(副表/从表)
CREATE TABLE employee(
    id INT PRIMARY KEY,
    empName VARCHAR(20),
    deptId INT,-- 把部门名称改为部门ID
    -- 声明一个外键约束
    CONSTRAINT emlyee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id)
    --           外键名称                  外键               参考表(参考字段)
)
  • 注意 :
    1)被约束的表称为副表,约束别人的表称为主表,外键设置在副表上的
    2)主表的参考字段通用为主键!
    3)添加数据 : 先添加主表,再添加副表
    4)修改数据 : 先修改副表,再修改主表
    5)删除数据 : 先删除副表,再删除主表

级联操作

  • 问题 : 当有了外键约束的时候,必须先修改或删除副表中的所有关联数据,才能修改或删除主表!但是,我们希望直接修改或删除主表数据,从而影响副表数据。可以使用级联操作实现!

  • 级联操作 :

    • 级联修改: ON UPDATE CASCADE
    • 级联删除: ON DELETE CASCADE
CREATE TABLE employee(
    id INT PRIMARY KEY,
    empName VARCHAR(20),
    deptId INT,-- 把部门名称改为部门ID
    -- 声明一个外键约束
    CONSTRAINT emlyee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id) ON UPDATE CASCADE ON DELETE CASCADE  -- ON CASCADE UPDATE :级联修改
    --           外键名称                  外键               参考表(参考字段)
)
注意: 级联操作必须在外键基础上使用

数据库设计

  1. 引入
  • 需求分析 - 需求分析师 -> 原始需求- > 抽取业务模型
    • 图书模型:图书名称,版本号,作者
    • 学生模型: 学号,学生姓名 手机号码
    • ......
    • 角色:学生 老师,图书管理员
    • <需求说明书>
  1. 需求设计
  • 概要设计 :
    • 抽取实体 : 业务模型 -> 实体模型(java 类 c++类) 内存class Book {name, bookNo, author}
    • 数据库设计 : 业务模型/实体模型 - > 数据模型 (硬盘)
      • 数据库表设计
  • 详细设计 : 类详细,属性和方法

三大范式

设计原则: 建议设计的表尽量遵守三大范式。

  • 第一范式: 要求表的每个字段必须是不可分割的独立单元

    • student : name -> 张小名|狗娃 -> 违反第一范式
    • sutdent : name, old_name -> 张小名, 狗娃 -> 符合第一范式
  • 第二范式: 在第一范式的基础上,要求每张表只表达一个意思。表的每个字段都和表的主键有依赖。

    • employee(员工): 员工编号 员工姓名 部门名称 订单名称-> 违反第二范式
    • 员工表 : 员工编号 员工姓名 部门名称, 订单表: 订单编号 订单名称 -> 符合第二范式
  • 第三范式: 在第二范式基础,要求每张表的主键之外的其他字段都只能和主键有直接决定依赖关系

    • 员工表 : 员工编号(主键), 员工姓名, 部门编号, 部门名-> 符合第二范式,违反第三范式(数据冗余高)
    • 员工表 : 员工编号(主键), 员工姓名, 部门编号, 部门表:部门编号, 部门名 -> 符合第三范式(降低数据冗余)

关联查询(多表查询)

  • 需求:查询员工及其所在部门(显示员工姓名,部门名称)

    1. 交叉连接查询(不推荐。产生笛卡尔乘积现象:4 * 4=16,有些是重复记录) : SELECT empName,deptName FROM employee,dept;
    • 多表查询规则:
      1)确定查询哪些表
      2)确定哪些哪些字段
      3)表与表之间连接条件 (规律:连接条件数量是表数量-1)
    1. 内连接查询:只有满足条件的结果才会显示(使用最频繁)
SELECT empName,deptName       -- 2)确定哪些哪些字段
    FROM employee,dept    -- 1)确定查询哪些表
    WHERE employee.deptId=dept.id  -- 3)表与表之间连接条件
- 内连接的另一种语法 : 
SELECT empName,deptName
    FROM employee
    INNER JOIN dept
    ON employee.deptId=dept.id;
- 使用别名
SELECT e.empName,d.deptName
    FROM employee e
    INNER JOIN dept d
    ON e.deptId=d.id;
  • 需求: 查询每个部门的员工

    • 预期结果:
      -- 软件开发部 张三
      -- 软件开发部 李四
      -- 应用维护部 王五
      -- 秘书部 陈六
      -- 总经办 null
  • 左[外]连接查询: 使用左边表的数据去匹配右边表的数据,如果符合连接条件的结果则显示,如果不符合连接条件则显示null(注意: 左外连接:左表的数据一定会完成显示)

SELECT d.deptName,e.empName
    FROM dept d
    LEFT OUTER JOIN employee e
    ON d.id=e.deptId;
  • 右[外]连接查询: 使用右边表的数据去匹配左边表的数据,如果符合连接条件的结果则显示,如果不符合连接条件则显示null(注意: 右外连接:右表的数据一定会完成显示)
SELECT d.deptName,e.empName
    FROM employee e
    RIGHT OUTER JOIN dept d
    ON d.id=e.deptId;
  • 自连接查询 :
    • 需求:查询员工及其上司
    • 预期结果:
      -- 张三 null
      -- 李四 张三
      -- 王五 李四
      -- 陈六 王五
SELECT e.empName,b.empName
    FROM employee e 
    LEFT OUTER JOIN employee b
    ON e.bossId=b.id;

存储过程

  1. 什么是存储过程 : 存储过程就是带有逻辑的sql语句, 存储过程带上流程控制语句(if, for, while)
  2. 存储过程特点
    1)执行效率非常快!存储过程是在数据库的服务器端执行的!
    2)移植性很差!不同数据库的存储过程是不能移植。
  3. 存储过程语法
-- 创建存储过程
DELIMITER $                          -- 声明存储过程的结束符
CREATE PROCEDURE pro_test()          --存储过程名称(参数列表)
BEGIN                                -- 开始
    -- 可以写多个sql语句;              -- sql语句+流程控制
    SELECT * FROM employee;
END $                                -- 结束 结束符

-- 执行存储过程
CALL pro_test();                     -- CALL 存储过程名称(参数);

参数:
IN : 表示输入参数,可以携带数据带存储过程中
OUT : 表示输出参数,可以从存储过程中返回结果
INOUT : 表示输入输出参数,既可以输入功能,也可以输出功能
  • 代码示例:
    1. 示例 :
-- 声明结束符
-- 创建存储过程
DELIMITER $
CREATE PROCEDURE pro_test()
BEGIN
    -- 可以写多个sql语句;
    SELECT * FROM employee;
END $
-- 执行存储过程
CALL pro_test();
  1. 带有输入参数的存储过程(传入一个员工的id,查询员工信息)
DELIMITER $
CREATE PROCEDURE pro_findById(IN eid INT)  -- IN: 输入参数
BEGIN
    SELECT * FROM employee WHERE id=eid;
END $ 
-- 调用
CALL pro_findById(4);
  1. 带有输出参数的存储过程
DELIMITER $
CREATE PROCEDURE pro_testOut(OUT str VARCHAR(20))  -- OUT:输出参数
BEGIN
        -- 给参数赋值
    SET str='hello_Java';
END $
  1. 删除存储过程 : DROP PROCEDURE pro_testOut;
  2. 带有输入输出参数的存储过程 :
DELIMITER $
CREATE PROCEDURE pro_testInOut(INOUT n INT)  -- INOUT: 输入输出参数
BEGIN
   -- 查看变量
   SELECT n;
   SET n =500;
END $
-- 调用
SET @n=10;
CALL pro_testInOut(@n);
SELECT @n;
  1. 带有条件判断的存储过程 : 输入一个整数: 如果是1则返回“星期一”, 如果2, 返回“星期二”, 如果3, 返回“星期三”。其他数字,返回“错误输入”;
DELIMITER $
CREATE PROCEDURE pro_testIf(IN num INT,OUT str VARCHAR(20))
BEGIN
    IF num=1 THEN
        SET str='星期一';
    ELSEIF num=2 THEN
        SET str='星期二';
    ELSEIF num=3 THEN
        SET str='星期三';
    ELSE
        SET str='输入错误';
    END IF;
END $
CALL pro_testIf(4,@str);
SELECT @str;
  1. 带有循环功能的存储过程 (输入一个整数,求和。例如,输入100,统计1-100的和)
DELIMITER $
CREATE PROCEDURE pro_testWhile(IN num INT,OUT result INT)
BEGIN
    -- 定义一个局部变量
    DECLARE i INT DEFAULT 1;
    DECLARE vsum INT DEFAULT 0;
    WHILE i<=num DO
          SET vsum = vsum+i;
          SET i=i+1;
    END WHILE;
    SET result=vsum;
END $
DROP PROCEDURE pro_testWhile;
CALL pro_testWhile(100,@result);
SELECT @result;
USE day16;
  1. 使用查询的结果赋值给变量(INTO)
DELIMITER $
CREATE PROCEDURE pro_findById2(IN eid INT,OUT vname VARCHAR(20) )
BEGIN
    SELECT empName INTO vname FROM employee WHERE id=eid;
END $
CALL pro_findById2(1,@NAME);
SELECT @NAME; 
  • 补充知识点 : mysql的变量

    • 全局变量 (内置变量) : mysql数据库内置的变量 (所有连接都起作用)
      • 查看所有全局变量 : show variables;
      • 查看某个全局变量 : select @@变量名
      • 修改全局变量 : set 变量名=新值
      • character_set_client : mysql服务器的接收数据的编码
      • character_set_results : mysql服务器输出数据的编码
    • 会话变量 : 只存在于当前客户端与数据库服务器端的一次连接当中。如果连接断开,那么会话变量全部丢失
      • 定义会话变量 : set @变量=值
      • 查看会话变量 : select @变量
    • 局部变量 : 在存储过程中使用的变量就叫局部变量。只要存储过程执行完毕,局部变量就丢失!
    • 示例 :
      1. 定义一个会话变量name
      2. 使用name会话变量接收存储过程的返回值 : CALL pro_testOut(@NAME);
      3. 查看变量值 : SELECT @NAME;
  • 练习 : 编写一个存储过程, 如果学生的英语平均分小于等于70分,则输出'一般'; 如果学生的英语平均分大于70分,且小于等于90分,则输出‘良好’; 如果学生的英语平均分大于90分,则输出‘优秀’

DELIMITER $
CREATE PROCEDURE pro_testAvg(OUT str VARCHAR(20))
BEGIN 
      -- 定义局部变量,接收平均分
      DECLARE savg DOUBLE;
      -- 计算英语平方分
      SELECT AVG(english) INTO savg FROM student2;
      IF savg<=70 THEN
           SET str='一般';
      ELSEIF savg>70 AND savg<=90 THEN
           SET str='良好';
      ELSE
       SET str='优秀';
      END IF;
END $
CALL pro_testAvg(@str);
SELECT @str;

触发器

  1. 触发器作用 : 当操作了某张表时,希望同时触发一些动作/行为,可以使用触发器完成!
    例如 : 当向员工表插入一条记录时,希望同时往日志表插入数据
-- 触发器
SELECT * FROM employee;

-- 日志表
CREATE TABLE test_log(
    id INT PRIMARY KEY AUTO_INCREMENT,
    content VARCHAR(100)
)

-- 需求: 当向员工表插入一条记录时,希望mysql自动同时往日志表插入数据
-- 创建触发器(添加)
CREATE TRIGGER tri_empAdd AFTER INSERT ON employee FOR EACH ROW    -- 当往员工表插入一条记录时
     INSERT INTO test_log(content) VALUES('员工表插入了一条记录');
     
-- 插入数据
INSERT INTO employee(id,empName,deptId) VALUES(7,'扎古斯',1);
INSERT INTO employee(id,empName,deptId) VALUES(8,'扎古斯2',1);

-- 创建触发器(修改)
CREATE TRIGGER tri_empUpd AFTER UPDATE ON employee FOR EACH ROW    -- 当往员工表修改一条记录时
     INSERT INTO test_log(content) VALUES('员工表修改了一条记录');
     
 -- 修改
 UPDATE employee SET empName='eric' WHERE id=7;
 
-- 创建触发器(删除)
CREATE TRIGGER tri_empDel AFTER DELETE ON employee FOR EACH ROW    -- 当往员工表删除一条记录时
     INSERT INTO test_log(content) VALUES('员工表删除了一条记录');
  
 -- 删除
 DELETE FROM employee WHERE id=7;
 SELECT * FROM employee;
 SELECT * FROM test_log;

mysql权限问题

  • mysql数据库权限问题:root :拥有所有权限(可以干任何事情)
  • 权限账户,只拥有部分权限(CURD)例如,只能操作某个数据库的某张表
  • 如何修改mysql的用户密码?
    • password: md5加密函数(单向加密) : SELECT PASSWORD('root'); -- *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
  • mysql数据库,用户配置 : user表
USE mysql;
SELECT * FROM USER;
  • 修改密码 : UPDATE USER SET PASSWORD=PASSWORD('123456') WHERE USER='root';
  • 分配权限账户 :
GRANT SELECT ON day16.employee TO 'eric'@'localhost' IDENTIFIED BY '123456';
GRANT DELETE ON day16.employee TO 'eric'@'localhost' IDENTIFIED BY '123456';

mysql备份和还原

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容