數據庫
多表之間的關聯最好是用邏輯上的關聯,而不是物理上的關聯,導致後期的擴展性差!!!
原生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是可選的
一對多查詢五種方式:
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用於連接多表,滿足條件就連接,不滿足就不連接
多對多查詢:
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";
子查詢:
給你部門的的名稱,查部門有哪些人? 第一步查到部門的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;
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()
刪:
ret=models.Book.objects.filter(pk=1).delete() --pk指主鍵 book=models.Book.objects.filter(pk=1).first() book.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)
查:
- 基於對象:
<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(): 從返回結果中剔除重複紀錄
- 基於雙下劃線:
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)
一對多:
- 增加
# 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))
- 修改
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)
- 刪除
多對多:
- 增加
#給紅樓夢這本書添加兩個作者(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])
- 刪除
#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])
- 修改
#修改紅樓夢這本書的作者爲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,]) #需要這樣傳
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)
-
一對多
#查詢紅樓夢這本書的出版社名字(正向,按字段) 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)
-
多對多
#紅樓夢這本書所有的作者(正向 字段) 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)
基於雙下劃線:
-
一對一
#查詢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)
-
一對多
#查詢紅樓夢這本書的出版社的名字(正向 按字段) ret=models.Book.objects.filter(name='紅樓夢').values('name','publish__name') print(ret) #查詢北京出版社出版的所有書的名字(反向 按表名小寫) ret=models.Publish.objects.filter(name='北京出版社').values('book__name') print(ret)
-
多對多
#紅樓夢這本書所有的作者名字(正向 按字段) 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)