数据库总结

多表之间的关联最好是用逻辑上的关联,而不是物理上的关联,导致后期的扩展性差!!!

原生sql

--mysql5.6

建表

一对多:

create table dept(id int primary key auto_increment,name char(20),job char(20));
create table emp(id int primary key auto_increment,name char(20),d_id int,foreign key(d_id) references dept(id));
一对多建表

多对多:

 1 create table teacher(id int primary key auto_increment,name char(15));
 2 create table student(id int primary key auto_increment,name char(15));
 3 #中间表
 4 create table tsr(
 5 id int primary key auto_increment,
 6 t_id int,s_id int,
 7 foreign key(t_id) references teacher(id),
 8 foreign key(s_id) references student(id)
 9 );
10 现在老师和学生 都是主表  关系表是从表
11 先插入老师和学生数据
12 insert into teacher values
13 (1,"高跟"),
14 (2,"矮跟");
15 
16 insert into student values
17 (1,"炜哥"),
18 (2,"仨疯");
19 
20 # 插入对应关系
21 insert into tsr values
22 (null,1,1),
23 (null,1,2),
24 (null,2,2);
25 
26 建表语句,中间表及插数据语句
多对多建表

一对一:

客户和学生
一个客户只能产生一个学生
一个学生只能对应一个客户
这样的关系是一对一
使用外键来关联,但是需要给外键加上唯一约束
客户和学生有主从关系,需要先建立客户,再建学生

create table customer(c_id int primary key auto_increment,
name char(20),phonenum char(11),addr char(20));

create table student1(s_id int primary key auto_increment,
name char(20),
class char(11),
number char(20),
housenum char(20),c_id int UNIQUE,
foreign key(c_id) references customer(c_id)
);

示例,建表语句
一对一建表

查询

单表查询:

不带关键字的查询
    select  {*|字段名|四则运行|聚合函数} from 表名 [where 条件]
    1.* 表示查询所有字段
    2.可以手动要查询的字段
    3.字段的值可以进行加减乘除运算
    4.聚合函数,用于统计
    where是可选的
View Code

一对多查询五种方式:

1.笛卡尔积查询
select *from 表1,表n
查询结果是
将左表中的每条记录,与右表中的每条记录都关联一遍
因为他不知道什么样的对应关系是正确,只能帮你都对一遍
a表有m条记录,b表有n条记录
笛卡尔积结果为m * n 记录

需要自己筛选出正确的关联关系
select *from emp,dept where emp.dept_id = dept.id;

2.内连接查询就是笛卡尔积查询:[inner] join
select *from emp [inner] join dept;
select *from emp inner join dept where emp.dept_id = dept.id;

3.左外链接查询:left join
select *from emp left join dept on emp.dept_id = dept.id;
左表数据全部显示,右表只显示匹配上的

4.右外链接查询:right join
select *from emp right join dept on emp.dept_id = dept.id;
右表数据全部显示,左表只显示匹配上的

内和外的理解:内指的是匹配上的数据,外指的是没匹配上的数据

5.全外连接:union
select *from emp full join dept on emp.dept_id = dept.id;  ##mysql不支持

 union: 合并查询结果,默认会去重
 select *from emp left join dept on emp.dept_id = dept.id
 union
 select *from emp right join dept on emp.dept_id = dept.id;

 union 去除重复数据,只能合并字段数量相同的表
 union all 不会去除重复数据

on,where关键字都是用于条件过滤,没有本质区别
在单表中where的作用是筛选过滤条件
只要是连接多表的条件就使用on,为了区分是单表还是多表,搞个新的名字就是on
在多表中on用于连接多表,满足条件就连接,不满足就不连接
View Code

 多对多查询:

create table stu(id int primary key auto_increment,name char(10));
create table tea(id int primary key auto_increment,name char(10));

#中间表
create table tsr(id int primary key auto_increment,t_id int,s_id int,
foreign key(s_id) references stu(id),
foreign key(s_id) references stu(id));
#插数据
insert into stu values(null,"张三"),(null,"李李四");
insert into tea values(null,"chuck"),(null,"wer");
insert into tsr values(null,1,1),(null,1,2),(null,2,2);
#查询语句,多表查询过滤条件用on
select *from stu join tea join tsr
on stu.id = tsr.s_id and tea.id = tsr.t_id
where tea.name = "chuck";
View Code

 子查询:

给你部门的的名称,查部门有哪些人?
    第一步查到部门的id
    第二部拿着id去员工表查询
select *from dept join emp on dept.id = emp.dept_id;

select *from emp join
# 使用子查询,得到每个部门的id以及部门的最高工资,形成一个虚拟表,把原始表和虚拟表连接在一起
(select dept_id,max(salary)as m from emp group by dept_id) as t1
# 如果这个人的部门编号等于虚拟表中的部门编号
on emp.dept_id = t1.dept_id
and
# 并且,如果这个人的工资等于虚拟表中的最高工资,就是你要找的人
emp.salary = t1.m;
View Code

orm增删改

--django

单表操作

增:

date类型,传的时候,可以传字符串(格式必须是:2018-06-17),可以传时间对象
ret=models.Book.objects.create(name='洪流吗',price=23.7,publish='北京出版社',pub_data='2018-06-17')

生成对象,再调save方法
book=models.Book(name='三国演义',price=46.89,publish='南京出版社',pub_data='2017-08-17')
book.save()
create或create-save

删:

ret=models.Book.objects.filter(pk=1).delete()  --pk指主键

book=models.Book.objects.filter(pk=1).first()
book.delete()
delete或取first-delete

改:

ret = models.Book.objects.filter(pk=2).update(name='ddd')

book=models.Book.objects.filter(pk=2).first()
book.name='XXX'
# 没有update这个方法的
# book.update()
# 既可以保存,又可以更新
book.save()

get方法
book = models.Book.objects.filter(pk=2).first()
# book拿到的是 book对象
#get查到的数据有且只有一条,如果多,少,都抛异常
book=models.Book.objects.get(name='XXX')
print(book.name)
update或赋值-save

查:

  • 基于对象:
<1> all():                  查询所有结果
   book=models.Book.objects.all()
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象              
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,超过一个或者没有都会抛出错误。              
<4> exclude(**kwargs):      它包含与所给筛选条件不匹配的对象,exclude = 排除
<5> order_by(*field):       对查询结果排序('-id'),取负号即反转
<6> reverse():              对查询结果反向排序,必须在order_by之后才能调用。
   book=models.Book.objects.order_by('price').reverse()
<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。 
   book=models.Book.objects.all().count()
<9> first():                返回第一条记录  
<10> last():                返回最后一条记录  
<11> exists():              如果QuerySet包含数据,就返回True,否则返回False 
<12> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后不是一系列model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<14> distinct():            从返回结果中剔除重复纪录
查询API
  • 基于双下划线:
price__in:__前为字段名,后为对应方法;
Book.objects.filter(price__in=[100,200,300]) --在列表范围内
Book.objects.filter(price__gt=100) --大于
Book.objects.filter(price__lt=100) --小于
Book.objects.filter(price__gte=100) --大于等于
Book.objects.filter(price__lte=100) --小于等于
Book.objects.filter(price__range=[100,200]) --在100-200之间
Book.objects.filter(title__contains="python") --包含Python
Book.objects.filter(title__icontains="python") --包含Python且区分大小写
Book.objects.filter(title__startswith="py") --以py开头
Book.objects.filter(pub_date__year=2012) --获取对应年份,月,日数据
基于双下划线模糊查询

多表操作

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    # 阅读数
    # reat_num=models.IntegerField(default=0)
    # 评论数
    # commit_num=models.IntegerField(default=0)

    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
    authors=models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)


class AuthorDatail(models.Model):
    nid = models.AutoField(primary_key=True)
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

models.py
创建模型
正向:关联关系在当前表中,从当前表去另一个表;正向查询按字段名
反向:关联关系不在当前表,从当前表去另一个表;反向查询按表名小写 

一对一:

  • 增加
author=models.Author.objects.create(name='小猴',age=16,author_detail_id=authordetail.pk)
create

一对多:

  • 增加
# publish:可以传一个publish对象
publish=models.Publish.objects.get(pk=1)
print(publish.name)
ret=models.Book.objects.create(name='西游记',price=88,publish_date='2018-09-12',publish=publish)

# publish_id:传一个id
ret=models.Book.objects.create(name='三国演义',price=32,publish_date='2018-07-12',publish_id=publish.pk)
print(type(ret.publish))
create--传对象或id
  • 修改
book=models.Book.objects.get(pk=2)
book.publish_id=2
# book.publish=出版社对象
book.save()

ret=models.Book.objects.filter(pk=2).update(publish=publish对象)

ret=models.Book.objects.filter(pk=2).update(publish_id=2)
save/update对象或ID
  • 删除

 

多对多:

  • 增加
#给红楼梦这本书添加两个作者(lqz,egon)
book = models.Book.objects.get(pk=1)
#相当于拿到了第三张表
往第三章表中添加纪录(问题来了?要传对象还是传id),都支持
book.authors.add(1,2)

lqz = models.Author.objects.get(pk=1)
egon = models.Author.objects.get(pk=2)
book.authors.add(lqz,egon)

book.authors.add(*[lqz,egon])
add对象或Id
  • 删除
#remove字段authors的id和名字都可以(名字为通过id获取的)
book.authors.remove(2)
book.authors.remove(egon,lqz)
book.authors.remove(1,2)
book.authors.remove(*[1,2])
book.authors.remove(*[lqz,egon])
remove对象或id
  • 修改
#修改红楼梦这本书的作者为lqz和egon
#先清空(清空这本的所有作者记录)
book.authors.clear()
book.authors.add(1,2)
#id
book.authors.set(*[6,])   #这样不行
book.authors.set([6,])   #需要这样传

#对象
lqz=models.Author.objects.get(pk=2)
set 必须传一个可迭代对象
book.authors.set([lqz,])   #需要这样传
clear+add或set

orm查询

基于对象的跨表查询(多次查询)
    一对一:
        -正向查询按字段
        -反向查询按表名小写
    一对多:
        -正向查询按字段(正向查询一定会查出一个来)
        -反向查询按表名小写_set.all()(返回结果是queryset对象)
    
    多对多:
        -正向查询按字段.all()(正向查询一定会查出多个来)
        -反向查询按表名小写_set.all()(返回结果是queryset对象)
    
基于双下划线的跨表查询
    -在filter和values中都可以做连表操作(也就是都可以写 __)
    -正向查询按字段
    -反向查询按表名小写
    
    无论以谁做基表,没有效率之分
查询之禅

 基于对象:

  • 一对一

#查询lqz作者的地址(正向查询,按字段)
lqz=models.Author.objects.filter(name='lqz').first()
# 作者详情对象
print(lqz.author_detail.addr)

#查询地址为上海的,作者的名字(反向查询,按表名小写)
authordetail=models.AuthorDatail.objects.filter(addr='上海').first()
#拿到的是作者对象authordetail.author
print(authordetail.author.name)
View Code
  • 一对多

#查询红楼梦这本书的出版社名字(正向,按字段)
book=models.Book.objects.get(pk=1)
#出版社对象 book.publish
print(book.publish.name)
#查询北京出版社出版的所有书名(反向查询按 表名小写_set.all())
publish=models.Publish.objects.get(pk=1)
#结果是queryset对象
books=publish.book_set.all()
for book in books:
    print(book.name)
#查询以红开头的
books=publish.book_set.all().filter(name__startswith='')
for book in books:
    print(book.name)
View Code
  • 多对多

#红楼梦这本书所有的作者(正向 字段)
book=models.Book.objects.get(pk=1)
# book.authors.all()拿到所有的作者,是一个queryset对象
authors=book.authors.all()
for author in authors:
    print(author.name)
#查询egon写的所有书(反向 表名小写_set.all())
egon=models.Author.objects.get(pk=2)
#拿到的是queryset对象
books=egon.book_set.all()
for book in books:
print(book.name)
View Code

 基于双下划线:

  • 一对一

#查询lqz作者的名字,地址(正向查询,按字段)
ret=models.Author.objects.filter(name='lqz').values('name','author_detail__addr')
print(ret)
#查询地址为上海的作者的名字(反向,按表名小写)
ret=models.AuthorDatail.objects.filter(addr='上海').values('addr','author__name','author__age')
print(ret.query)
print(ret)
View Code
  • 一对多

#查询红楼梦这本书的出版社的名字(正向  按字段)
ret=models.Book.objects.filter(name='红楼梦').values('name','publish__name')
print(ret)
#查询北京出版社出版的所有书的名字(反向  按表名小写)
ret=models.Publish.objects.filter(name='北京出版社').values('book__name')
print(ret)
View Code
  • 多对多

#红楼梦这本书所有的作者名字(正向  按字段)
ret=models.Author.objects.filter(book__name='红楼梦').values('name')
print(ret)

ret=models.Book.objects.filter(name='红楼梦').values('authors__name')
print(ret)
#egon出版的所有书的名字(反向 表名小写)
ret=models.Book.objects.filter(authors__name='egon').values('name')
print(ret)
ret=models.Author.objects.filter(name='egon').values('book__name')
print(ret)
#查询北京出版社出版过的所有书籍的名字以及作者的姓名
ret=models.Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
print(ret)
ret=models.Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
print(ret)
ret=models.Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')
print(ret)

#地址是以北开头的作者出版过的所有书籍名称以及出版社名称
#以authordetial为基表
ret = models.AuthorDatail.objects.filter(addr__startswith='').values('author__book__name',
                                                                      'author__book__publish__name')
print(ret)
#以book为基表
ret=models.Book.objects.filter(authors__author_detail__addr__startswith='').values('name','publish__name')
print(ret.query)
#以author为基表
ret=models.Author.objects.filter(author_detail__addr__startswith='').values('book__name','book__publish__name')
print(ret.query)
View Code
posted @ 2019-03-16 16:35  ChuckXue  阅读(214)  评论(0编辑  收藏  举报