一、什么是关系?

1、分析:有这么一组数据关于学生的数据

学号、姓名、年龄、住址、成绩、学科、学科(语文、数学、英语)

我们应该怎么去设计储存这些数据呢?

2、先考虑第一范式:列不可在拆分原则

  这里面学科包含了三个学科,所以学科拆分为:语文学科、数学学科、英语学科,同样的成绩也要拆分为语文成绩、数学成绩、英语成绩。这样既满足了第一范式,各列可以设计为:

学号、姓名、年龄、住址、语文学科、数学学科、英语学科、语文成绩、数学成绩、英语成绩

3、在考虑第二范式:唯一标识

  也就是说在1NF的基础上,非Key属性必须完全依赖于主键,第二范式(2NF)要求数据库表中的每个实例或记录必须可以被唯一地区分。选取一个能区分每个实体的属性或属性组,作为实体的唯一标识。即确定主键,我们可以选取学号为主键

4、接着在考虑第三范式:

  确保表中各列与主键列直接相关,而不是间接相关。即各列与主键列都是一种直接依赖关系,则满足第三范式。 

  不难发现在这么多列中,年龄、住址和成绩、学科没有直接关系,也就是说我考多少分,和年龄及住址都无关,他们都是学生的信息,但都是不相关的信息,所以根据第三范式,我们需要将这些数据根据其相关性拆分为多个表。

5、表与表之间的关系

  如果我们要想找到张三的语文成绩,那么我们就必须去成绩表中查找,因为成绩表中保存的所有人的所有学科成绩。但是在成绩表中查找的时候,需要从省标中查到张三的学号(stu_id)和从学科表中查到语文学科(sub_id)的编号,这个时候这三张表就发生了关系,这也就是关系型数据库的精髓,而根据这种表与表之间的关系也会衍生出很多的查询的高级操作

二、外键(foreign key)

外键约束:用于限制主表与从表数据完整性。

alter table scores  add constraint 'stu_score_fk' foreign key(stu_id) references students(stu_id);
  • 将scores表的stu_id外键关联到students表的stu_id字段(说明:这里scores表里面字段stu_id和students表里的stu_id重名了,最好避免重名)
  • 每个外键都有一个名字,可以通过constraint指定
  • 存在外键的表,称之为从表(子表),外键指向的表,称之为主表(父表)。
  • 作用:保持数据一致性,完整性,主要目的是控制存储在外键表(从表)中的数据。例如,此时在从表插入或者修改数据时,如果stu_id的值在students表中不存在则会报错
  • 外键也可以在创建表时可以直接创建约束

语法:

 foreign key (外键字段) references 主表名 (关联字段)
例如:
create table scores(
id int primary key auto_increment,
stu_id int,
sub_id int,
score decimal(,),
foreign key(stuid) references students(id),
foreign key(subid) references subjects(id)
);

[主表记录删除时的动作] [主表记录更新时的动作],此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下,可以设置为null.前提是该外键列,没有not null。

三、外键的级联操作

  • 在删除或者修改students表的数据时,如果这个stu_id值在scores中已经存在,则会抛异常
  • 推荐使用逻辑删除,还可以解决这个问题
  • 可以创建表时指定级联操作,也可以在创建表后再修改外键的级联操作
alter table scores add constraint stu_sco foreign key(stu_id) references students(stu_id) on delete cascade;

除了on delete还有on update都要注意级联操作

级联操作的类型包括:

  • restrict(限制):默认值,抛异常,拒绝父表删除或者更新
  • cascade(级联):如果主表的记录删掉,则从表中相关联的记录都将被删除,如果主表修改记录,则从表记录也将被修改
  • set null:将外键设置为空
  • no action:什么都不做

四、链接查询

在讲解第一个问题关系的时候,我们提到了,如果要查找张三的语文成绩,需要用到三个表,当我们查询结果来源于多张表的时候就需要使用连接查询

链接查询关键:找到表间的关系,当前的关系是

  • students表的stu_id---scores表的stu_id
  • subjects表的sub_id---scores表的sub_id

select students.stu_name,subjects.sub_name,scores.score
from scores
inner join students on scores.stu_id=students.stu_id
inner join subjects on scores.sub_id=subjects.sub_id
where students.stu_name='张三' and subjects.sub_name='语文';
+----------+----------+-------+
| stu_name | sub_name | score |
+----------+----------+-------+
| 张三 | 语文 | |
+----------+----------+-------+
  • 结论:当需要对有关系的多张表进行查询时,需要使用连接join
  • 连接查询分类如下:

    • 表A inner join 表B:表A与表B匹配的行会出现在结果中
    • 表A left join 表B:表A与表B匹配的行会出现在结果中,外加表A中独有的数据,未对应的数据使用null填充
    • 表A right join 表B:表A与表B匹配的行会出现在结果中,外加表B中独有的数据,未对应的数据使用null填充
    • 在查询或条件中推荐使用“表名.列名”的语法
    • 如果多个表中列名不重复可以省略“表名.”部分
    • 如果表的名称太长,可以在表名后面使用' as 简写名'或' 简写名',为表起个临时的简写名称

五、视图

  视图就像我们python里面的函数一样,对SQL语言代码块的封装

    • 对于复杂的查询,在多次使用后,维护是一件非常麻烦的事情
    • 解决:定义视图
    • 视图本质就是对查询的一个封装
    • 定义视图
create view stuscore as select students.stu_name,subjects.sub_name,scores.score from scores inner join students on scores.stu_id=students.stu_id inner join subjects on scores.sub_id=subjects.sub_id;

这句话的意思就是用stuscore就相当于后面红色很长的一段SQL语句:

mysql> select *from stuscore;
+----------+----------+-------+
| stu_name | sub_name | score |
+----------+----------+-------+
| 张三 | 语文 | |
| 张三 | 数学 | |
| 张三 | 英语 | |
| 李四 | 语文 | |
| 李四 | 数学 | |
| 李四 | 英语 | |
| 王五 | 语文 | |
| 王五 | 数学 | |
| 王五 | 英语 | |
| 赵六 | 语文 | |
| 赵六 | 数学 | |
| 赵六 | 英语 | |
| 侯七 | 语文 | |
| 侯七 | 数学 | |
| 侯七 | 英语 | |
+----------+----------+-------+

六、自连接查询

  有时在信息查询时需要进行对自身连接(自连接)自连接是单边操作,所以我们需要为表定义别名。举例说明,下面是一个新的学生成绩表,在下表中我们要找到比张三成绩高的。

+--------+----------+-----------+
| stu_id | stu_name | stu_score |
+--------+----------+-----------+
| | 张三 | |
| | 李四 | |
| | 王五 | |
| | 赵六 | |
| | 侯七 | |
+--------+----------+-----------+

  一般情况我们看到这张表我们第一时间用语句进行操作:

select * from Score where stu_score>;

  可想而知,这是有多么简单,假设你并不知道数据库中张三的成绩是90或者数据量相当庞大呢?作为一个数据库管理员,我们就要用别的方式迅速找出所需要的数据。

方式一:分步查找:最简单的一种方式,也是最容易想到的操作“

select stu_score from Score where stu_name='张三';//得出张三的成绩
select *from Score where stu_score>;

  与采用自连接的方式相比,这种方法需要对中间结果进行人工干预,显然不利于程序中的自动处理操作。

方式二:自连接方式:

select * from Score as a,Score as b where a.stu_name='张三' and a.stu_score<b.stu_score;
+--------+----------+-----------+--------+----------+-----------+
| stu_id | stu_name | stu_score | stu_id | stu_name | stu_score |
+--------+----------+-----------+--------+----------+-----------+
| | 张三 | | | 赵六 | |
| | 张三 | | | 侯七 | |
+--------+----------+-----------+--------+----------+-----------+

如果不想把张三的信息打印出来我们可以调整SQL语句为:

select b.* from Stu_score as a,Stu_score as b where a.stu_name='张三' and a.stu_score<b.stu_score;
+--------+----------+-----------+
| stu_id | stu_name | stu_score |
+--------+----------+-----------+
| | 赵六 | |
| | 侯七 | |
+--------+----------+-----------+

注意:别名 a,b虽然名称不同,但是同一个表,定义别名的目的是更方便在自身进行删选。
执行select通过(中间表)所得到的b.*,,就是最终结果。

七、子查询

子查询也是常用的一种方式,就是在select里嵌套select。还是上面的例子,我们用子查询实现如下:

select * from Stu_score where stu_score>(select stu_score from Stu_score where stu_name='张三'); 
+--------+----------+-----------+
| stu_id | stu_name | stu_score |
+--------+----------+-----------+
| | 赵六 | |
| | 侯七 | |
+--------+----------+-----------+

八、内置函数

1、字符串函数

1、查看字符的ascii码值ascii(str),str是空串时返回0

mysql> select ascii('a');
+------------+
| ascii('a') |
+------------+
| |
+------------+

2、查看ascii码值对应的字符char(数字)

mysql> select char();
+----------+
| char() |
+----------+
| a |
+----------+

3、拼接字符串concat(str1,str2...)

select concat(,,'ab');
+--------------------+
| concat(,,'ab') |
+--------------------+
| 1234ab |
+--------------------+

4、包含字符个数length(str)

mysql> select length('abc');
+---------------+
| length('abc') |
+---------------+
| |
+---------------+

5、截取字符串

  • left(str,len)返回字符串str的左端len个字符
  • right(str,len)返回字符串str的右端len个字符
  • substring(str,pos,len)返回字符串str的位置pos起len个字符
mysql> select substring('abc123',,);
+-------------------------+
| substring('abc123',,) |
+-------------------------+
| bc1 |
+-------------------------+

6、去除空格

  • ltrim(str)返回删除了左空格的字符串str
  • rtrim(str)返回删除了右空格的字符串str
  • trim([方向 remstr from str)返回从某侧删除remstr后的字符串str,方向词包括both、leading、trailing,表示两侧、左、右
mysql> select trim('  bar   ');
+------------------+
| trim(' bar ') |
+------------------+
| bar |
+------------------+
mysql> select trim(leading 'x' FROM 'xxxbarxxx');
+------------------------------------+
| trim(leading 'x' FROM 'xxxbarxxx') |
+------------------------------------+
| barxxx |
+------------------------------------+
mysql> select trim(trailing 'x' FROM 'xxxbarxxx');
+-------------------------------------+
| trim(trailing 'x' FROM 'xxxbarxxx') |
+-------------------------------------+
| xxxbar |
+-------------------------------------+
mysql> select trim(both 'x' FROM 'xxxbarxxx');
+---------------------------------+
| trim(both 'x' FROM 'xxxbarxxx') |
+---------------------------------+
| bar |
+---------------------------------+

7、替换字符串replace(str,from_str,to_str)

mysql> select replace('abc123','','def');
+-------------------------------+
| replace('abc123','','def') |
+-------------------------------+
| abcdef |
+-------------------------------+

8、大小写转换,函数如下

  • lower(str)
  • upper(str)
mysql> select lower('aBcD');
+---------------+
| lower('aBcD') |
+---------------+
| abcd |
+---------------+

2、数学函数

1、求绝对值abs(n)

mysql> select abs(-);
+----------+
| abs(-) |
+----------+
| |
+----------+

2、求m除以n的余数mod(m,n),同运算符%

mysql> select mod(,);
+-----------+
| mod(,) |
+-----------+
| |
+-----------+ mysql> select %;
+------+
| % |
+------+
| |
+------+

3、floor(n),表示不大于n的最大整数

mysql> select floor(2.3);
+------------+
| floor(2.3) |
+------------+
| |
+------------+

4、ceiling(n),表示不小于n的最大整数

mysql> select ceiling(2.3);
+--------------+
| ceiling(2.3) |
+--------------+
| |
+--------------+

5、求四舍五入值round(n,d),n表示原数,d表示小数位置,默认为0

mysql> select round(1.6);
+------------+
| round(1.6) |
+------------+
| |
+------------+

6、求x的y次幂pow(x,y)

mysql> select pow(,);
+----------+
| pow(,) |
+----------+
| |
+----------+

7、随机数rand(),值为0-1.0的浮点数

mysql> select rand();
+--------------------+
| rand() |
+--------------------+
| 0.0713081630610937 |
+--------------------+

3、日期时间函数

  • 获取子值,语法如下

    • year(date)返回date的年份(范围在1000到9999)
    • month(date)返回date中的月份数值
    • day(date)返回date中的日期数值
    • hour(time)返回time的小时数(范围是0到23)
    • minute(time)返回time的分钟数(范围是0到59)
    • second(time)返回time的秒数(范围是0到59)
mysql> select year('2019-7-11');
+-------------------+
| year('2019-7-11') |
+-------------------+
| |
+-------------------+
  • 日期计算,使用+-运算符,数字后面的关键字为year、month、day、hour、minute、second
mysql> select '2019-7-11'+interval  day;
+----------------------------+
| '2019-7-11'+interval day |
+----------------------------+
| -- |
+----------------------------+

日期格式化date_format(date,format),format参数可用的值如下

  • 获取年%Y,返回4位的整数

    * 获取年%y,返回2位的整数

    * 获取月%m,值为1-12的整数

  • 获取日%d,返回整数

    * 获取时%H,值为0-23的整数

    * 获取时%h,值为1-12的整数

    * 获取分%i,值为0-59的整数

    * 获取秒%s,值为0-59的整数

九、事物

  • 当一个业务逻辑需要多个sql语句完成时,如果其中某条sql语句出错,则希望整个操作都退回
  • 使用事务可以完成退回的功能,保证业务逻辑的正确性
  • 事务四大特性(简称ACID)
    • 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行
    • 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致
    • 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的
    • 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障
  • 要求:表的类型必须是innodb或bdb类型,才可以对此表使用事务
  • 查看表的创建语句
show create table Stu_score;
  • 修改表的类型:alter table '表名' engine=innodb;
alter table Stu_score engine=innodb;
  • 事务语句
开启begin;
提交commit;
回滚rollback;

  在begin;后面写我们要操作的SQL语句组合也就是我们所谓的要执行的事物,但是这个时候写好的SQL语句就算我们回车之后,也不会执行,知道commit;执行之后才会被执行到数据库中,rollback回滚是我们begin;之后发现我们写错了,或者不想执行了,都可以在commit;之前回滚到上一次commit;的状态,很像版本控制器SVN和GIT一样

python数据库-MySQL数据库高级查询操作(51)的更多相关文章

  1. python数据库-mongoDB的高级查询操作(55)

    一.MongoDB索引 为什么使用索引? 假设有一本书,你想看第六章第六节讲的是什么,你会怎么做,一般人肯定去看目录,找到这一节对应的页数,然后翻到这一页.这就是目录索引,帮助读者快速找到想要的章节. ...

  2. 使用python读取mysql数据库并进行数据的操作

    (一)环境的配置 使用python调用mysql数据库要引进一些库. 目前我使用的python版本是python3.6.引进库为pymysql 其他对应的库可以有以下选择: mysqldb,oursq ...

  3. MySQL/MariaDB数据库的多表查询操作

    MySQL/MariaDB数据库的多表查询操作 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.单表查询小试牛刀 [root@node105.yinzhengjie.org.cn ...

  4. python之(mysql数据库操作)

    前言:关心3步骤(此文章只针对python自动化根基展开描述) 什么是mysql数据库操作?  答:利用python对mysql数据库进行增, 删, 改, 查 操作 为什么要用python对mysql ...

  5. Python与Mysql 数据库的连接,以及查询。

    python与mysql数据库的连接: pymysql是python中对数据库的连接模块:因此应当首先安装pymysql数据库模块. 执行pip install pymysql 命令. 然后在pyth ...

  6. MySQL 高级查询操作

    目录 MySQL 高级查询操作 一.预告 二.简单查询 三.显示筛选 四.存储过程 五.查询语句 1.作为变量 2.函数调用 3.写入数据表 备注 附表一 附表二 相关文献 博客提示 MySQL 高级 ...

  7. Python安装MySQL数据库模块

    背景 折腾: [记录]使用Python操作MySQL数据库 的过程中,需要去安装MySQLdb. 下载MySQLdb 去官网: http://pypi.python.org/pypi/MySQL-py ...

  8. python专题-Mysql数据库(python3._+ PyMysql)

    之前写过一篇 Python使用MySQL数据库的博客,主要使用的是Python2和MySQLdb驱动. python使用mysql数据库 Python2 ---> Python3 MySQLdb ...

  9. python专题-Mysql数据库(python2._+ Mysqldb)

    Python使用MySQL数据库 MySQLdb驱动从2014年1月停止了维护. Python2 MySQLdb 一,安装mysql 如果是windows 用户,mysql 的安装非常简单,直接下载安 ...

随机推荐

  1. maven_默认新建项目jdk1.6_默认配置

    <?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...

  2. 就服务器项目部署debug谈谈自己的感受

    前言 学校小组Project那些外国人啥也不会, 基本上我一个人全包了前端和后端, 说实话这些天来也感受到了写一个比较拿得出手的web确实也不是这么容易的, 特别是我没什么项目经验, 很多时候碰到问题 ...

  3. Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式

    原文:Android Camera2 拍照(三)--切换摄像头,延时拍摄和闪光模式 一.切换摄像头 在前后摄像头之间切换,首先需要关闭之前打开的摄像头,关闭preview,之后重新打开新的摄像头,重新 ...

  4. JavaScript 中的12种循环遍历方法

    原文:JavaScript 中的12种循环遍历方法 题目:请介绍 JavaScript 中有哪些循环和遍历的方法,说说它们的应用场景和优缺点? 1.for 循环 let arr = [1,2,3];f ...

  5. facebook javascript api 使用

    官方api文档:http://developers.facebook.com/docs 先简单的介绍下创建一个app(https://developers.facebook.com/apps),

  6. huawei 通过BGP的团体属性进行路由控制

    网络拓扑 XRV1的配置: =========================================================================== # sysname ...

  7. Win10《芒果TV》商店版更新v3.2.1:优化手机版卡顿,修复推送故障

    此版本是小版本更新,主要是修复上一版本发布后暴露的部分体验问题,以免进一步扩大影响,小幅修复后更新上线. 芒果TV UWP V3.2.1更新内容清单: 1.优化和修复列表预加载机制的本地保存丢失导致的 ...

  8. Android 9.0 Dialog不显示

    Tester报了一个bug,大概如下: 页面:Activity1 dialog1(半透明遮罩样式) Activity2 dialog2 场景:Activity1弹出dialog1,dialog1弹出a ...

  9. select ,update 加锁

    最近我在弄一个项目,其中涉及到了数据批量导入数据库的过程,在导入数据的时候,每一条数据会生成一个唯一标识,但是我发现有些数据的标识重复了.我在网上查了一下说这是“数据库 并发性”的问题解决方案,上锁. ...

  10. Android零基础入门第83节:Activity间数据传递方法汇总

    在Activity间传递的数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity间数据的传递. 一.常用数据类型 在前面几节我们只学习了一些常用类型的数据传 ...