mysql 3_mysql3
回顧
字段類型(列類型): 數值型, 時間日期型和字符串類型
數值型: 整型和小數型(浮點型和定點型)
時間日期型: datetime, date,time,timestamp, year
字符串類型: 定長, 變長, 文件字符串(text和blob), 枚舉和集合
Mysql記錄長度: 65535個字節, varchar達不到理論長度, NULL占用一個字節, text文本不占用記錄長度(但是本身占據十個字節)
字段屬性: 空屬性, 列描述, 默認值
字段屬性
主鍵, 唯一鍵和自增長.
主鍵
主鍵: primary
key,主要的鍵. 一張表只能有一個字段可以使用對應的鍵, 用來唯一的約束該字段里面的數據, 不能重復: 這種稱之為主鍵.
一張表只能有最多一個主鍵.
增加主鍵
SQL操作中有多種方式可以給表增加主鍵: 大體分為三種.
方案1: 在創建表的時候,直接在字段之后,跟primary key關鍵字(主鍵本身不允許為空)
優點: 非常直接; 缺點: 只能使用一個字段作為主鍵
方案2: 在創建表的時候, 在所有的字段之后, 使用primary key(主鍵字段列表)來創建主鍵(如果有多個字段作為主鍵,可以是復合主鍵)
方案3: 當表已經創建好之后, 額外追加主鍵: 可以通過修改表字段屬性, 也可以直接追加.
Alter table 表名? add primary key(字段列表);
前提: 表中字段對應的數據本身是獨立的(不重復)
主鍵約束
主鍵對應的字段中的數據不允許重復: 一旦重復,數據操作失敗(增和改)
更新主鍵 & 刪除主鍵
沒有辦法更新主鍵: 主鍵必須先刪除,才能增加.
Alter table 表名 drop primary key;
主鍵分類
在實際創建表的過程中, 很少使用真實業務數據作為主鍵字段(業務主鍵,如學號,課程號); 大部分的時候是使用邏輯性的字段(字段沒有業務含義,值是什么都沒有關系), 將這種字段主鍵稱之為邏輯主鍵.
Create table my_student(
Id int primary key auto_increment comment ‘邏輯主鍵: 自增長’,??? -- 邏輯主鍵
Number char(10) not null? comment ‘學號’,
Name varchar(10) not null
)
自動增長
自增長: 當對應的字段,不給值,或者說給默認值,或者給NULL的時候, 會自動的被系統觸發, 系統會從當前字段中已有的最大值再進行+1操作,得到一個新的在不同的字段.
自增長通常是跟主鍵搭配.
新增自增長
自增長特點:
auto_increment
任何一個字段要做自增長必須前提是本身是一個索引(key一欄有值)
自增長字段必須是數字(整型)
一張表最多只能有一個自增長
自增長使用
當自增長被給定的值為NULL或者默認值的時候會觸發自動增長.
自增長如果對應的字段輸入了值,那么自增長失效: 但是下一次還是能夠正確的自增長(從最大值+1)
如何確定下一次是什么自增長呢?
可以通過查看表創建語句看到.
修改自增長
自增長如果是涉及到字段改變:
必須先刪除自增長,后增加(一張表只能有一個自增長)
修改當前自增長已經存在的值:
修改只能比當前已有的自增長的最大值大,不能小(小不生效)
Alter table 表名 auto_increment? = 值;
向上修改可以
思考: 為什么自增長是從1開始?為什么每次都是自增1呢?
所有系統的變現(如字符集,校對集)都是由系統內部的變量進行控制的.
查看自增長對應的變量:
show variables like ‘auto_increment%’;
可以修改變量實現不同的效果:
修改是對整個數據修改,而不是單張表: (修改是會話級)
Set auto_increment_increment = 5; -- 一次自增5
測試效果: 自動使用自增長
刪除自增長
自增長是字段的一個屬性: 可以通過modify來進行修改(保證字段沒有auto_increment即可)
Alter table 表名 modify 字段 類型;
唯一鍵
一張表往往有很多字段需要具有唯一性,數據不能重復: 但是一張表中只能有一個主鍵: 唯一鍵(unique key)就可以解決表中有多個字段需要唯一性約束的問題.
唯一鍵的本質與主鍵差不多: 唯一鍵默認的允許自動為空,而且可以多個為空(空字段不參與唯一性比較)
增加唯一鍵
基本與主鍵差不多: 三種方案
方案1: 在創建表的時候,字段之后直接跟unique/ unique key
方案2: 在所有的字段之后增加unique key(字段列表); -- 復合唯一鍵
方案3: 在創建表之后增加唯一鍵
唯一鍵約束
唯一鍵與主鍵本質相同: 唯一的區別就是唯一鍵默認允許為空,而且是多個為空.
如果唯一鍵也不允許為空: 與主鍵的約束作用是一致的.
更新唯一鍵 & 刪除唯一鍵
更新唯一鍵: 先刪除后新增(唯一鍵可以有多個: 可以不刪除).
刪除唯一鍵
Alter table 表名 drop unique key; -- 錯誤: 唯一鍵有多個
Alter table 表名 drop index 索引名字; -- 唯一鍵默認的使用字段名作為索引名字
索引
幾乎所有的索引都是建立在字段之上.
索引: 系統根據某種算法, 將已有的數據(未來可能新增的數據),單獨建立一個文件: 文件能夠實現快速的匹配數據, 并且能夠快速的找到對應表中的記錄.
索引的意義
提升查詢數據的效率
約束數據的有效性(唯一性等)
增加索引的前提條件: 索引本身會產生索引文件(有時候有可能比數據文件還大) ,會非常耗費磁盤空間.
如果某個字段需要作為查詢的條件經常使用, 那么可以使用索引(一定會想辦法增加);
如果某個字段需要進行數據的有效性約束, 也可能使用索引(主鍵,唯一鍵)
Mysql中提供了多種索引
主鍵索引: primary key
唯一索引: unique key
全文索引: fulltext index
普通索引: index
全文索引: 針對文章內部的關鍵字進行索引
全文索引最大的問題: 在于如何確定關鍵字
英文很容易: 英文單詞與單詞之間有空格
中文很難: 沒有空格, 而且中文可以各種隨意組合(分詞: sphinx)
關系
將實體與實體的關系, 反應到最終數據庫表的設計上來: 將關系分成三種: 一對一, 一對多(多對一)和多對多.
所有的關系都是指的表與表之間的關系.
一對一
一對一: 一張表的一條記錄一定只能與另外一張表的一條記錄進行對應; 反之亦然.
學生表: 姓名,性別,年齡,身高,體重,婚姻狀況, 籍貫, 家庭住址,緊急聯系人
Id(P)
姓名
性別
年齡
體重
身高
婚姻
籍貫
住址
聯系人
表設計成以上這種形式: 符合要求. 其中姓名,性別,年齡,身高,體重屬于常用數據; 但是婚姻,籍貫,住址和聯系人屬于不常用數據.
如果每次查詢都是查詢所有數據,不常用的數據就會影響效率, 實際又不用.
解決方案: 將常用的和不常用的信息分離存儲,分成兩張表
常用信息表
Id(P)
姓名
性別
年齡
體重
身高
1
不常用信息表: 保證不常用信息與常用信息一定能夠對應上: 找一個具有唯一性(確定記錄)的字段來共同連接兩張表
Id(P)
婚姻
籍貫
住址
聯系人
2
1
一個常用表中的一條記錄: 永遠只能在一張不常用表中匹配一條記錄;反過來,一個不常用表中的一條記錄在常用表中也只能匹配一條記錄: 一對一的關系
一對多
一對多: 一張表中有一條記錄可以對應另外一張表中的多條記錄; 但是返回過, 另外一張表的一條記錄只能對應第一張表的一條記錄. 這種關系就是一對多或者多對一.
母親與孩子的關系: 母親,孩子兩個實體
媽媽表
ID(P)
名字
年齡
性別
孩子表
ID(P)
名字
年齡
性別
以上關系: 一個媽媽可以在孩子表中找到多條記錄(也有可能是一條); 但是一個孩子只能找到一個媽媽: 是一種典型的一對多的關系.
但是以上設計: 解決了實體的設計表問題, 但是沒有解決關系問題: 孩子找不出媽,媽也找不到孩子.
解決方案: 在某一張表中增加一個字段,能夠找到另外一張表的中記錄: 應該在孩子表中增加一個字段指向媽媽表: 因為孩子表的記錄只能匹配到一條媽媽表的記錄.
媽媽表
ID(P)
名字
年齡
性別
孩子表
ID(P)
名字
年齡
性別
媽媽ID
媽媽表主鍵
多對多
多對多: 一張表中(A)的一條記錄能夠對應另外一張表(B)中的多條記錄; 同時B表中的一條記錄也能對應A表中的多條記錄: 多對多的關系
老師教學: 老師和學生
老師表
T_ID(P)
姓名
性別
1
A
男
2
B
女
學生表
S_ID(P)
姓名
性別
1
張三
男
2
小芳
女
以上設計方案: 實現了實體的設計, 但是沒有維護實體的關系.
一個老師教過多個學生; 一個學生也被多個老師教過.
解決方案: 在學生表中增加老師字段: 不管在哪張表中增加字段, 都會出現一個問題: 該字段要保存多個數據, 而且是與其他表有關系的字段, 不符合表設計規范: 增加一張新表: 專門維護兩張表之間的關系
老師表
T_ID(P)
姓名
性別
1
A
男
2
B
女
學生表
S_ID(P)
姓名
性別
1
張三
男
2
小芳
女
中間關系表: 老師與學生的關系
ID
T_ID(老師)
S_ID(學生)
1
1
1
2
1
2
3
2
1
4
增加中間表之后: 中間表與老師表形成了一對多的關系: 而且中間表是多表,維護了能夠唯一找到一表的關系; 同樣的,學生表與中間表也是一個一對多的關系: 一對多的關系可以匹配到關聯表之間的數據.
學生找老師: 找出學生id -> 中間表尋找匹配記錄(多條) -> 老師表匹配(一條)
老師找學生: 找出老師id -> 中間表尋找匹配記錄(多條) -> 學生表匹配(一條)
范式
范式: Normal
Format, 是一種離散數學中的知識, 是為了解決一種數據的存儲與優化的問題: 保存數據的存儲之后, 凡是能夠通過關系尋找出來的數據,堅決不再重復存儲: 終極目標是為了減少數據的冗余.
范式: 是一種分層結構的規范, 分為六層: 每一次層都比上一層更加嚴格: 若要滿足下一層范式,前提是滿足上一層范式.
六層范式:
1NF,2NF,3NF...6NF, 1NF是最底層,要求最低;6NF最高層,最嚴格.
Mysql屬于關系型數據庫: 有空間浪費: 也是致力于節省存儲空間: 與范式所有解決的問題不謀而合: 在設計數據庫的時候, 會利用到范式來指導設計.
但是數據庫不單是要解決空間問題,要保證效率問題: 范式只為解決空間問題, 所以數據庫的設計又不可能完全按照范式的要求實現: 一般情況下,只有前三種范式需要滿足.
范式在數據庫的設計當中是有指導意義: 但是不是強制規范.
1NF
第一范式: 在設計表存儲數據的時候, 如果表中設計的字段存儲的數據,在取出來使用之前還需要額外的處理(拆分),那么說表的設計不滿足第一范式: 第一范式要求字段的數據具有原子性: 不可再分.
講師代課表
講師
性別
班級
教室
代課時間
代課時間(開始,結束)
朱元璋
Male
php0226
D302
30天
2014-02-27,2014-05-05
朱元璋
Male
php0320
B206
30天
2014-03-21,2014-05-30
李世民
Male
php0320
B206
15天
2014-06-01,2014-06-20
上表設計不存在問題: 但是如果需求是將數據查出來之后,要求顯示一個老師從什么時候開始上課,到什么時候節課: 需要將代課時間進行拆分: 不符合1NF, 數據不具有原子性, 可以再拆分.
解決方案: 將代課時間拆分成兩個字段就解決問題.
2NF
第二范式: 在數據表設計的過程中,如果有復合主鍵(多字段主鍵), 且表中有字段并不是由整個主鍵來確定, 而是依賴主鍵中的某個字段(主鍵的部分): 存在字段依賴主鍵的部分的問題, 稱之為部分依賴: 第二范式就是要解決表設計不允許出現部分依賴.
講師帶課表
以上表中: 因為講師沒有辦法作為獨立主鍵, 需要結合班級才能作為主鍵(復合主鍵: 一個老師在一個班永遠只帶一個階段的課): 代課時間,開始和結束字段都與當前的代課主鍵(講師和班級): 但是性別并不依賴班級, 教室不依賴講師: 性別只依賴講師, 教室只依賴班級: 出現了性別和教室依賴主鍵中的一部分: 部分依賴.不符合第二范式.
解決方案1: 可以將性別與講師單獨成表, 班級與教室也單獨成表.
解決方案2: 取消復合主鍵, 使用邏輯主鍵
ID = 講師 + 班級(業務邏輯約束: 復合唯一鍵)
3NF
要滿足第三范式,必須滿足第二范式.
第三范式: 理論上講,應該一張表中的所有字段都應該直接依賴主鍵(邏輯主鍵: 代表的是業務主鍵), 如果表設計中存在一個字段, 并不直接依賴主鍵,而是通過某個非主鍵字段依賴,最終實現依賴主鍵: 把這種不是直接依賴主鍵,而是依賴非主鍵字段的依賴關系稱之為傳遞依賴. 第三范式就是要解決傳遞依賴的問題.
講師帶課表
以上設計方案中: 性別依賴講師存在, 講師依賴主鍵; 教室依賴班級,班級依賴主鍵: 性別和教室都存在傳遞依賴.
解決方案: 將存在傳遞依賴的字段,以及依賴的字段本身單獨取出,形成一個單獨的表, 然后在需要對應的信息的時候, 使用對應的實體表的主鍵加進來.
講師代課表
講師表??????????????????????????????????????????????????????????? 班級表
講師表: ID = 講師??????????????????????????????????????? 班級表中: ID = 班級
逆規范化
有時候, 在設計表的時候,如果一張表中有幾個字段是需要從另外的表中去獲取信息. 理論上講, 的確可以獲取到想要的數據, 但是就是效率低一點. 會刻意的在某些表中,不去保存另外表的主鍵(邏輯主鍵), 而是直接保存想要的數據信息: 這樣一來,在查詢數據的時候, 一張表可以直接提供數據, 而不需要多表查詢(效率低), 但是會導致數據冗余增加.
如講師代課信息表
逆規范化: 磁盤利用率與效率的對抗
數據高級操作
數據操作: 增刪改查
新增數據
基本語法
Insert into 表名 [(字段列表)] values
(值列表);
在數據插入的時候, 假設主鍵對應的值已經存在: 插入一定會失敗!
主鍵沖突
當主鍵存在沖突的時候(Duplicate
key),可以選擇性的進行處理: 更新和替換
主鍵沖突: 更新操作
Insert into 表名[(字段列表:包含主鍵)] values(值列表) on duplicate key update 字段 = 新值;
主鍵沖突: 替換
Replace into 表名 [(字段列表:包含主鍵)] values(值列表);
蠕蟲復制
蠕蟲復制: 從已有的數據中去獲取數據,然后將數據又進行新增操作: 數據成倍的增加.
表創建高級操作: 從已有表創建新表(復制表結構)
Create table 表名 like 數據庫.表名;
蠕蟲復制: 先查出數據, 然后將查出的數據新增一遍
Insert into 表名[(字段列表)] select 字段列表/* from 數據表名;
蠕蟲復制的意義
從已有表拷貝數據到新表中
可以迅速的讓表中的數據膨脹到一定的數量級: 測試表的壓力以及效率
更新數據
基本語法
Update 表名 set 字段 = 值 [where條件];
高級新增語法
Update 表名 set 字段 = 值 [where條件] [limit 更新數量];
刪除數據
與更新類似: 可以通過limit來限制數量
Delete from 表名 [where條件] [limit 數量];
刪除: 如果表中存在主鍵自增長,那么當刪除之后, 自增長不會還原
思路: 數據的刪除是不會改變表結構, 只能刪除表后重建表
Truncate 表名;????? -- 先刪除改變,后新增改變
查詢數據
基本語法
Select 字段列表/* from 表名 [where條件];
完整語法
Select [select選項] 字段列表[字段別名]/* from 數據源 [where條件子句] [group by子句] [having子句] [order by子句] [limit 子句];
Select選項
Select選項: select對查出來的結果的處理方式
All: 默認的,保留所有的結果
Distinct: 去重, 查出來的結果,將重復給去除(所有字段都相同)
字段別名
字段別名: 當數據進行查詢出來的時候, 有時候名字并一定就滿足需求(多表查詢的時候, 會有同名字段). 需要對字段名進行重命名: 別名
語法
字段名 [as] 別名;
數據源
數據源: 數據的來源, 關系型數據庫的來源都是數據表: 本質上只要保證數據類似二維表,最終都可以作為數據源.
數據源分為多種: 單表數據源, 多表數據源, 查詢語句
單表數據源: select
* from 表名;
多表數據源: select*
from 表名1,表名2...;
從一張表中取出一條記錄,去另外一張表中匹配所有記錄,而且全部保留:(記錄數和字段數),將這種結果成為: 笛卡爾積(交叉連接): 笛卡爾積沒什么卵用, 所以應該盡量避免.
子查詢: 數據的來源是一條查詢語句(查詢語句的結果是二維表)
Select * from (select 語句) as 表名;
Where子句
Where子句: 用來判斷數據,篩選數據.
Where子句返回結果: 0或者1, 0代表false,1代表true.
判斷條件:
比較運算符: >, =, <= ,!= ,<>, =, like, between and,
in/not in
邏輯運算符: &&(and), ||(or), !(not)
Where原理: where是唯一一個直接從磁盤獲取數據的時候就開始判斷的條件: 從磁盤取出一條記錄, 開始進行where判斷: 判斷的結果如果成立保存到內存;如果失敗直接放棄.
條件查詢1: 要求找出學生id為1或者3或者5的學生
條件查詢2: 查出區間落在180,190身高之間的學生:
Between本身是閉區間; between左邊的值必須小于或者等于右邊的值
Group by子句
Group by:分組的意思, 根據某個字段進行分組(相同的放一組,不同的分到不同的組)
基本語法:
group? by 字段名;
分組的意思: 是為了統計數據(按組統計: 按分組字段進行數據統計)
SQL提供了一系列統計函數
Count(): 統計分組后的記錄數: 每一組有多少記錄
Max():??? 統計每組中最大的值
Min(): 統計最小值
Avg(): 統計平均值
Sum(): 統計和
Count函數: 里面可以使用兩種參數: *代表統計記錄,字段名代表統計對應的字段(NULL不統計)
分組會自動排序: 根據分組字段:默認升序
Group by 字段 [asc|desc];??? -- 對分組的結果然后合并之后的整個結果進行排序
多字段分組: 先根據一個字段進行分組,然后對分組后的結果再次按照其他字段進行分組
有一個函數: 可以對分組的結果中的某個字段進行字符串連接(保留該組所有的某個字段): group_concat(字段);
回溯統計: with
rollup: 任何一個分組后都會有一個小組,
最后都需要向上級分組進行匯報統計: 根據當前分組的字段. 這就是回溯統計: 回溯統計的時候會將分組字段置空.
多字段回溯: 考慮第一層分組會有此回溯: 第二次分組要看第一次分組的組數, 組數是多少,回溯就是多少,然后加上第一層回溯即可.
Having子句
Having子句: 與where子句一樣: 進行條件判斷的.
Where是針對磁盤數據進行判斷: 進入到內存之后,會進行分組操作: 分組結果就需要having來處理.
Having能做where能做的幾乎所有事情, 但是where卻不能做having能做的很多事情.
分組統計的結果或者說統計函數都只有having能夠使用.
Having能夠使用字段別名: where不能: where是從磁盤取數據,而名字只可能是字段名: 別名是在字段進入到內存后才會產生.
Order by子句
Order by: 排序, 根據某個字段進行升序或者降序排序, 依賴校對集.
使用基本語法
Order by 字段名 [asc|desc]; -- asc是升序(默認的),desc是降序
排序可以進行多字段排序: 先根據某個字段進行排序, 然后排序好的內部,再按照某個數據進行再次排序:
Limit子句
Limit子句是一種限制結果的語句: 限制數量.
Limit有兩種使用方式
方案1: 只用來限制長度(數據量): limit 數據量;
方案2: 限制起始位置,限制數量: limit 起始位置,長度;
Limit方案2主要用來實現數據的分頁: 為用戶節省時間,提交服務器的響應效率, 減少資源的浪費.
對于用戶來講: 可以點擊的分頁按鈕: 1,2,3,4
對于服務器來講: 根據用戶選擇的頁碼來獲取不同的數據: limit offset,length;
Length: 每頁顯示的數據量: 基本不變
Offset: offset = (頁碼 - 1) * 每頁顯示量
總結
以上是生活随笔為你收集整理的mysql 3_mysql3的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 8.0.12解压版安装教程_
- 下一篇: php后端mysql,【后端开发】PHP