數據庫

數據庫

多表之間的關聯最好是用邏輯上的關聯,而不是物理上的關聯,導致後期的擴展性差!!!

原生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 閱讀(...) 評論(...) 編輯 收藏
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章