目錄python
models中全部的字段類型其實本質就那幾種,整形varchar什麼的,都沒有實際的約束做用,雖然在models中沒有任何限制做用,可是仍是要分門別類,對於校驗性組件校驗很是有用
就好比說郵箱類型,你在輸入郵箱的時候若是不按照郵箱格式輸入,瞎雞兒輸入會提示你不合法,雖然輸入的是字符串,可是不是規定的郵箱字符串git
字段 | 描述 |
---|---|
AutoField | int自增列,必須填入參數 primary_key=True。當model中若是沒有自增列,則自動會建立一個列名爲id的列。 |
IntegerField | 一個整數類型,範圍在 -2147483648 to 2147483647。(通常不用它來存手機號(位數也不夠),直接用字符串存,) |
BigIntegerField | |
CharField | 字符類型對應MySQL的varchar類型,必須提供max_length參數, max_length表示字符長度。 |
DateField | 日期時間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],至關於Python中的datetime.datetime()實例。 |
DecimalField | 10進制小數, max_digits,小數總長度 ,decimal_places,小數位長度 |
EmailField | email字段,內部仍是varchar(254) |
BooleanField | 布爾值,傳True或False,自動轉成1/0 |
TextField | 存儲大段文本 |
FileField | 專門用來存放文件路徑,傳值的時候,直接傳文件對象,將路徑保存到數據庫 |
關係字段 | 描述 |
ForeignKey | 關係字段,外鍵類型在ORM中用來表示外鍵關聯關係,通常把ForeignKey字段設置在 '一對多'中'多'的一方。 |
OneToOneField | 一對一字段。 |
ManyToManyField | 多對多表關係而且這一張多對多的關係表是有Django自動幫你建 |
參數 | 描述 |
---|---|
null | 用於表示某個字段能夠爲空。 |
unique | 若是設置爲unique=True 則該字段在此表中必須是惟一的 。 |
db_index | 若是db_index=True 則表明着爲此字段設置索引。 |
default | 爲該字段設置默認值。 |
DateField和DateTimeField | 描述 |
auto_now_add | 配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。 |
auto_now | 配置上auto_now=True,每次更新數據記錄的時候會更新該字段。 |
關係字段參數 | 描述 |
to | 設置要關聯的表 |
to_field | 設置要關聯的表的字段 |
on_delete | 當刪除關聯表中的數據時,當前表與其關聯的行的行爲。 |
db_constraint | 是否在數據庫中建立外鍵約束,默認爲True。 |
Django中的CharField對應的MySQL數據庫中的varchar類型,沒有設置對應char類型的字段,sql
可是Django容許咱們自定義新的字段,下面我來自定義對應於數據庫的char類型數據庫
自定義字段在實際項目應用中可能會常常用到django
from django.db import models # Create your models here. #Django中沒有對應的char類型字段,可是咱們能夠本身建立 class FixCharField(models.Field): ''' 自定義的char類型的字段類 ''' def __init__(self,max_length,*args,**kwargs): self.max_length=max_length super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): ''' 限定生成的數據庫表字段類型char,長度爲max_length指定的值 :param connection: :return: ''' return 'char(%s)'%self.max_length #應用上面自定義的char類型 class Class(models.Model): id=models.AutoField(primary_key=True) title=models.CharField(max_length=32) class_name=FixCharField(max_length=16)
字段合集和對應關係併發
咱們來建立一張表:app
models.py: class Books(models.Model): title = models.CharField(max_length=254) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField() 將表同步到MySQL中: python3 manage.py makemigrations python3 manage.py migrate
而後咱們在django測試文件中,若是單純的測試某個py文件,須要手動配置測試腳本函數
app01/tests.py: # Create your tests here. import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings") import django django.setup() from app01 import models # 下面開始寫測試的代碼。 # 建立數據------------------------------------------------------------------------ # 1. create 方法 models.Books.objects.create(title='三國演義',price=123,publish_date='2019-11-11') from datetime import date ctime = date.today() models.Books.objects.create(title='紅樓夢',price=888,publish_date=ctime) # 2. 利用對象的綁定方法建立數據 book_obj = models.Books(title='西遊記',price=666,publish_date='2000-11-11') book_obj.save() # 插入的數據 # id title price publish_date # 4 三國演義 123 2019-11-11 # 5 紅樓夢 888 2019-11-27 # 6 西遊記 666 2000-11-11 # 修改數據------------------------------------------------------------------------ ''' 利用filter 自動查詢當前表的主鍵字段,pk表明primary_key filter查詢出來的是一個queryset對象: 只要是queryset的對象就能夠無限制的調用queryset的方法 只要是queryset的對象就能夠點query查看當前結果內部對應的sql語句 ''' # 1. 利用queryset方法修改數據 models.Books.objects.filter(pk=4).update(price=444) # 2. 利用對象方法修改數據 book_obj = models.Books.objects.get(pk=1) book_obj.price = 222 book_obj.save() # 不推薦使用,推薦使用queryset方法 ''' 利用對象修改,內部實際上是將全部的字段從新寫進去 get 和 filter的區別: filter 獲取到的是一個queryset對象,相似於一個列表,沒有數據的時候不會報錯 get獲取到的數據就是數據自己,可是沒有數據的時候會報錯 ''' # 刪除數據------------------------------------------------------------------------ # 1. 利用queryset方法 :delete() models.Books.objects.filter(pk=4).delete() # 2. 對象的方法 book_obj = models.Books.objects.get(pk=4) book_obj.delete() # 若是你想直接查看全部的orm語句內部對應的sql語句,能夠在配置文件中配置: settings.py: LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
方法(加括號使用) | 描述 |
---|---|
all | 查詢全部,返回QuerySet對象 |
filter | 篩選,至關於原生SQL的where條件,返回QuerySet對象 |
get | 篩選,獲取數據對象自己,若是不存在報錯,而且查詢條件必須是惟一的。 |
first | 取QuerySet對象中第一個數據對象 |
last | 取QuerySet對象中最後一個數據對象 |
count | 統計數據的條數 |
values | 獲取數據對象中指定的字段的值,返回列表套字典的QuerySet對象 |
values_list | 獲取數據對象中指定的字段的值,返回列表套元組的QuerySet對象 |
order_by | 指定字段進行排序,默認升序,在字段前加- 是降序 |
reverse | 顛倒順序,前提是顛倒的對象必須有順序,也就是order_by事後的 |
exclude | 查詢排除什麼以外,返回QuerySet對象 |
exists | 判斷查詢結果是否有值,返回布爾值 |
distinct | 對指定字段查詢出來的結果進行去重操做 |
# 查詢數據 13 條------------------------------------------------------------------------ # 1. all() 查詢全部,返回queryset對象 print(models.Books.objects.all()) # 2. filter() 篩選 至關於原生sql語句裏面的where關鍵字,返回queryset對象 print(models.Books.objects.filter(pk=4)) # 3. get() 篩選 獲取的數據是對象自己,數據不存在直接報錯,而且查詢條件必須惟一,返回數據對象自己 print(models.Books.objects.get(pk=4)) # 4. first() 獲取queryset對象中第一個數據對象 返回數據對象 print(models.Books.objects.filter(pk=4).first()) # 5. last() 獲取queryset對象中最後一個數據對象 返回數據對象 print(models.Books.objects.filter(pk=4).last()) # 6. count() 統計數據的條數 返回數字 print(models.Books.objects.count()) # 7. values() 獲取數據對象中指定的字段的值,能夠指定多個,返回queryset對象,列表套字典 print(models.Books.objects.values('title','price')) # 8. values_list() 獲取數據對象中指定的字段的值,能夠指定多個,返回queryset對象,列表套元組 print(models.Books.objects.values_list('title','price')) # 9. order_by() 按照指定的字段排序,默認是升序,在字段前面加 - 是降序 print(models.Books.objects.order_by('pk').values('pk')) print(models.Books.objects.order_by('-pk').values('pk')) # 10. reverse() 顛倒順序,前提是顛倒的對象必須有順序,排序以後的 print(models.Books.objects.order_by('pk').reverse().values('pk')) # 11. exclude() 查詢條件排除什麼 print(models.Books.objects.exclude(pk=4).values('pk')) # 12. exists() 判斷查詢結果是否有值,返回的是布爾值 print(models.Books.objects.exists()) # 13. distinct() 對查詢結果去重,前提是數據徹底相同的狀況下 print(models.Books.objects.values('title','price').distinct())
方法 | 描述 |
---|---|
**__gt** | 字段大於什麼什麼值 |
**__lt** | 字段小於什麼什麼值 |
**__gte** | 字段大於等於什麼值 |
**__lte** | 字段小於等於什麼值 |
**__in** | 字段是什麼或什麼的值,or的關係 |
**__range** | 字段是什麼和什麼之間的值,btwen..and... |
**__year** | 字段的年份是什麼什麼的值 |
**__month** | 字段的月份是什麼什麼的值 |
# 下劃線查詢------------------------------------------------------------------------ # 1. 查詢價格大於500的書 print(models.Books.objects.filter(price__gt=500).values('title')) # 2. 查詢價格小於500的書籍 print(models.Books.objects.filter(price__lt=500).values('title')) # 3. 查詢價格大於等於500的書籍 print(models.Books.objects.filter(price__gte=500).values('title')) # 4. 查詢價格小於等於500的書籍 print(models.Books.objects.filter(price__lte=500).values('title')) # 5. 查詢價格是222 或 444 或 500 的書籍 print(models.Books.objects.filter(price__in=[222,444,500]).values('title')) # 6. 查詢價格在200到800之間的書籍 顧頭也顧尾 print(models.Books.objects.filter(price__range=(200,800)).values('title')) # 7. 查詢出版日期是2019年的書籍 print(models.Books.objects.filter(publish_date__year='2019').values('title')) # 8. 查詢出版日期是11月份的書籍 print(models.Books.objects.filter(publish_date__month='11').values('title'))
MySQL中的模糊查詢,關鍵字like,模糊匹配的符號:%
、_
測試
方法 | 描述 |
---|---|
**__startswith** | 字段的值以什麼什麼開頭的值 |
**__endswith** | 字段的值以什麼什麼結尾的值 |
**__contanins** | 字段的值包含什麼什麼的值,區分大小寫 |
**__icontanins** | 字段的值包含什麼什麼的值,不區分大小寫 |
# 模糊查詢------------------------------------------------------------------------ # 1. 查詢書籍是以三開頭的書 print(models.Books.objects.filter(title__startswith='三').values('title')) # 2. 查詢書籍是以三結尾的書 print(models.Books.objects.filter(title__endswith='三').values('title')) # 3. 查詢書籍名稱中包含遊字的書籍 print(models.Books.objects.filter(title__contains='遊').values('title')) # 4. 查詢書籍名稱中包含字母p的書籍,區分大小寫 print(models.Books.objects.filter(title__contains='p').values('title')) # 5. 查詢書籍名稱中包含字母p的書籍,區分大小寫 print(models.Books.objects.filter(title__icontains='p').values('title'))
爲了方便操做,咱們建立圖書管理系統相關表來演示多表操做atom
models.py: class Book(models.Model): title = models.CharField(max_length=254) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField(auto_now_add=True) ''' auto_now :每次修改數據的時候,會自動更新時間 auto_now_add :當數據建立出來的時候,自動將建立時間記錄下來 ''' publish = models.ForeignKey(to='Publish') authors = models.ManyToManyField(to='Author') class Publish(models.Model): name = models.CharField(max_length=254) addr = models.CharField(max_length=254) class Author(models.Model): name = models.CharField(max_length=254) email = models.EmailField(max_length=254) author_detail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model): phone = models.BigIntegerField() add = models.CharField(max_length=254)
# 一對多字段數據的增刪改查------------------------------------------------------------------------ # 一對一字段的數據的修改和一對多同樣的。 # 增 # 第一種方式: publish_obj = models.Publish.objects.filter(pk=1).first() models.Book.objects.create(title='紅樓夢',price=444,publish=publish_obj) # 第二種方式: models.Book.objects.create(title='三國演義',price=222,publish_id=1) # 改 # 第一種方式: models.Book.objects.filter(pk=2).update(publish_id=2) # 第二種方式: publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.filter(pk=2).update(publish=publish_obj) # 刪 默認就是級聯刪除,級聯更新 models.Publish.objects.filter(pk=1).delete()
方法 | 描述 |
---|---|
add | 可以在第三張表中添加數據既支持傳數字,也支持傳對象,能夠傳多個值 |
set | 修改第三張表中的數據,須要傳一個可迭代對象進去例如元組,列表,容器類元素能夠是數字或者對象 |
remove | 刪除第三張表中的數據,既支持傳數字,也支持傳對象,能夠傳多個值 |
clear | 清空 刪除書籍相關的記錄,下線,括號內不須要傳遞參數 |
# 多對多字段數據的增刪改查------------------------------------------------------------------------ # 增 book_obj = models.Book.objects.filter(pk=2).first() # print(book_obj.authors) # app01.Author.None 表示着已經跨到第三張表了 # 給當前這一本書綁定做者,能夠寫多個 book_obj.authors.add(1) book_obj.authors.add(1,2) # 也能夠增長對象 author_obj1 = models.Author.objects.filter(pk=1).first() author_obj2 = models.Author.objects.filter(pk=2).first() book_obj.authors.add(author_obj1,author_obj2) ''' add 方法: 可以在第三張表中添加數據 既支持傳數字,也支持傳對象,能夠傳多個值 ''' # 改 # 修改id爲2的書籍的做者 book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.set((1,)) book_obj.authors.set((1,2)) # 也能夠修改成對象 author_obj1 = models.Author.objects.filter(pk=1).first() author_obj2 = models.Author.objects.filter(pk=2).first() book_obj.authors.set((author_obj1,author_obj2)) ''' set 方法: 修改第三張表中的數據, 須要傳一個可迭代對象進去例如元組,列表, 容器類元素能夠是數字或者對象 ''' # 刪 # 刪除id爲2的書籍的做者 book_obj = models.Book.objects.filter(pk=2).first() book_obj.author.remove(1,2) # 也能夠傳對象 author_obj1 = models.Author.objects.filter(pk=1).first() author_obj2 = models.Author.objects.filter(pk=2).first() book_obj.author.remove(author_obj1, author_obj2) ''' remove 方法: 刪除第三張表中的數據,既支持傳數字,也支持傳對象,能夠傳多個值 ''' # 清空: # 刪除id爲2 的書籍(包括做者信息也刪除) book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.clear() ''' clear 方法: 清空 刪除書籍相關的記錄,下線,括號內不須要傳遞參數 '''
在使用跨表查詢的時候,要注意一點,
要明白關係字段在哪一方?
從有關係字段的那一方查的話就是正向查詢,查詢按關係字段查詢查。
從沒有關係字段的那一方查的話就是反向查詢,查詢按小寫的表名查。
方法 | 描述 |
---|---|
all() | 當正向查詢點擊外鍵字段數據有多個的狀況下也就是多對多查詢,須要加.all() |
**_set** | 反向查詢的時候 表名小寫而且加_set |
子查詢
# 跨表查詢------------------------------------------------------------------------ # 基於對象的跨表查詢 # 1. 查詢書籍主鍵爲2的出版社名稱 # 正向查詢,先查書籍對象,一對多查詢 book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.publish.name) # 2. 查詢書籍主鍵爲2的做者姓名 # 正向查詢,先查書籍對象,多對多查詢 book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.authors) # app01.Author.None print(book_obj.authors.all().values('name')) # 3. 查詢做者是qinyj的手機號碼 # 正向查詢,先查做者對象,一對一查詢 author_obj = models.Author.objects.filter(name='qinyj').first() print(author_obj.author_detail.phone) ''' 何時須要加 all: 當正向查詢點擊外鍵字段數據有多個的狀況下 也就是多對多查詢,須要加.all() ''' # 4. 查詢出版社是東方出版社出版過的書籍 # 反向查詢,先查出版社對象,一對多查詢 publish_obj = models.Publish.objects.filter(name='東方出版社').first() print(publish_obj.book_set.all().values('title')) # 5. 查詢做者是qinyj寫過的書籍 # 反向查詢,先查做者對象,多對多查詢 author_obj = models.Author.objects.filter(name='qinyj').first() print(author_obj.book_set.all().values('title')) # 6. 查詢手機號是111111的做者姓名 # 反向查詢,先查做者詳情表的對象,一對一查詢 author_detail_obj = models.AuthorDetail.objects.filter(phone='111111').first() print(author_detail_obj.author.name) ''' 何時反向查詢的時候表名小寫而且加_set 一對多 多對多 一對一不須要加 '''
聯表查詢
雙下劃線,鏈式操做:__
# 基於雙下劃線的跨表查詢 聯表操做------------------------------------------------------------------------ # 1. 查詢書籍id爲2的出版社名稱 # 正向查詢: # values中寫外鍵名就至關於跨到外鍵字段所在的表中了 print(models.Book.objects.filter(pk=2).values('publish__name')) # 反向查詢: print(models.Publish.objects.filter(book__pk=2).values('name')) # 2. 查詢書籍id爲2的做者的姓名 # 正向查詢: print(models.Book.objects.filter(pk=2).values('authors__name')) # 反向查詢: print(models.Author.objects.filter(book__pk=2).values('name')) # 3. 查詢做者是qinyj的地址 # 正向查詢: print(models.Author.objects.filter(name='qinyj').values('author_detail__add')) # 反向查詢: print(models.AuthorDetail.objects.filter(author__name='qinyj').values('add')) # 4. 查詢出版社是東方出版社出版過的書的名字 # 正向查詢: print(models.Book.objects.filter(publish__name='東方出版社').values('title')) # 反向查詢: print(models.Publish.objects.filter(name='東方出版社').values('book__title')) # 5. 查詢書籍id是2的做者的手機號 # 正向查詢: print(models.Book.objects.filter(pk=2).values('authors__author_detail__phone')) # 反向查詢: print(models.Author.objects.filter(book__pk=2).values('author_detail__phone'))
aggregate
聚合函數 | 描述 |
---|---|
Max | 最大值 |
Min | 最小值 |
Sum | 求和 |
Count | 計數 |
Avg | 平均數 |
''' 聚合函數 ''' from django.db.models import Max,Min,Count,Avg,Sum # 篩選出價格最高的書籍 print(models.Book.objects.aggregate(ct=Count('price'))) # {'ct': 2} # 篩選出價格最低的書籍 print(models.Book.objects.aggregate(mn=Min('price'))) # {'mn': Decimal('222.00')} # 求書籍價格總和 print(models.Book.objects.aggregate(sm=Sum('price'))) # {'sm': Decimal('666.00')} # 求書籍價格平均值 print(models.Book.objects.aggregate(ag=Avg('price'))) # {'ag': 333.0} # 聯用 print(models.Book.objects.aggregate(Max('price')),Min('price'),Sum('price'),Count('price'))
annotate
''' 分組查詢,一般和聚合函數一塊兒使用 ''' # 1. 統計每一本書的 書名和對應的做者個數 print(models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')) # 2. 統計每各出版社賣的最便宜的書的價格 print(models.Publish.objects.annotate(book_num=Min('book__price')).values('name','book_num')) # 3. 按照指定的字段進行分組 print(models.Publish.objects.values('name').annotate(max_price=Max('book__price')).values('name','max_price')) # 4. 統計不止一個做者的圖書 # 首先拿到書對應的做者數,再篩選出大於一的圖書,做者個數 print(models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')) # 5. 查詢每一個做者出的書的總價格 print(models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price'))
''' F 查詢 ''' from django.db.models import F,Q # 1. 查詢庫存數大於賣出數的書籍 print(models.Book.objects.filter(kucun_num__gt=F('maichu_num')).values('title')) # 2. 將全部書的價格都上漲100塊 models.Book.objects.all().update(price=F('price')+100) # 3. 將全部書的名字後面都加上 後綴名 from django.db.models.functions import Concat from django.db.models import Value models.Book.objects.update(title=Concat(F('title'),Value('新款'))) ''' Q 查詢 ''' # 1. 查詢書籍名是三國演義或者 庫存數是500的書籍 print(models.Book.objects.filter(title='三國演義',kucun_num=500)) # 默認是and的關係 print(models.Book.objects.filter(Q(title='三國演義') | Q(kucun_num=500))) # 用了 | 就是or的關係 print(models.Book.objects.filter(~Q(title='三國演義') | Q(kucun_num=500))) # 用了 | 就是or的關係 ''' Q對象高級用法 ''' q = Q() q.connector = 'or' # 默認是and,能夠改爲or q.children.append(('title','三國演義')) q.children.append(('kucun_num',500)) print(models.Book.objects.filter(q))
還記得在Mysql數據庫中的事務操做嗎?
在MySQL中只有使用Innodb數據庫引擎的數據庫或表才支持使用事務
事務必須知足4個條件(ACID):
from django.db import transaction with transaction.atomic(): # 在縮進的代碼中書寫數據庫的操做 # 該縮進下的全部代碼,都是一個事務 pass # 對整個view視圖開啓事務 @transaction.atomic def index(request): //ORM操做 return ....
1.建立一個項目,新建一個APP(基礎操做,這裏再也不贅述)
2.經過ORM建立生成表
from django.db import models class UserInfo(models.Model): username = models.CharField("用戶",max_length=32) balance = models.CharField("餘額",max_length=32)
注意啊:踩過的坑,涉及金融計算,涉及小數啊,要求特別精確的,咱們用字符串存儲。
若是是金融計算的話,咱們用一個decimal來進行計算。
3.咱們給數據庫加兩條數據,用來模擬兩個用戶之間的轉帳
4.配置URL
5.建立對應的視圖函數
from django.shortcuts import render,HttpResponse from app01 import models from django.db import transaction from django.db.models import F def index(request): try: with transaction.atomic(): models.UserInfo.object.filter(id=1).update(balance=F("balance")-100) models.UserInfo.object.filter(id=2).update(balance=F("balance")+100) except Exception as e: return HttpResponse("出現錯誤<%s>"%str(e)) return HttpResponse("執行成功")
當咱們訪問index的時候,會進行一次轉帳操做
6.如今,咱們讓他報錯
from django.shortcuts import render,HttpResponse from app01 import models from django.db import transaction from django.db.models import F def index(request): try: with transaction.atomic(): models.UserInfo.object.filter(id=1).update(balance=F("balance")-100) raise 一個錯誤 models.UserInfo.object.filter(id=2).update(balance=F("balance")+100) except Exception as e: return HttpResponse("出現錯誤<%s>"%str(e)) return HttpResponse("執行成功")
咱們再次查看數據庫文件,若是沒有數據的原子性操做,咱們第一條sql執行完報錯,那錢確定是減去了
可是,咱們進行的是原子性的操做,你會發現錢沒有減誒。
完美,沒毛病
範式(Normal Form),縮寫NF,規範化形式,簡稱範式。
目的是增長數據有效性,減小數據冗餘,提升存儲效率
數據庫中的每個字段,必須是不可拆分的最小單位。
即一個字段就表示一個意思,表中不能同時有2個字段來表示同一個意思
正例:
根據業務需求來合理使用行政區域
反例:
其中 address 能夠再分爲省、市、地區(縣)、街道、詳細地址,違反了第一範式。
表中全部字段都必須有意義,一個表只描述某一個事物
主鍵存在的意義就是惟一的標識表中的某一條記錄,若是某一列和該行記錄不要緊,也就不必存在。
反例:
此表中,天氣(weather字段)和用戶沒啥關係,也就不存在依賴關係,所不符合 第二範式。正確的作法應)該刪除此列,若有其餘須要可單獨存在一張表中。
表中不能有其餘表中存在的、存儲相同信息的字段,一般是經過外鍵去創建關聯,外鍵約束
反例:
上面是一個訂單表,字段從左至右以此是:訂單id、買家id、買家名稱、買家性別、買家年齡、訂單狀態。其中字段buyer_name、buyer_gender、buyer_age 是依賴於字段 buyer_info_id,違反 第二範式。
正例:
訂單表
買家信息表