關係型數據庫建議在E-R模型的基礎上,咱們須要根據產品經理的設計策劃,抽取出來模型與關係,制定出表結構,這是項目開始的第一步python
在開發中有不少設計數據庫的軟件,經常使用的如power designer,db desinger等,這些軟件能夠直觀的看到實體及實體間的關係mysql
設計數據庫,多是由專門的數據庫設計人員完成,也多是由開發組成員完成,通常是項目經理帶領組員來完成sql
就是咱們根據開發需求,要保存到數據庫中做爲一張表存在的事物。實體的名稱最終會變成表名數據庫
實體會有屬性,實體的屬性就是描述這個事物的內容,實體的屬性最終會在表中做爲字段存在。服務器
實體與實體之間會存在關係,這種關係通常就是根據三範式提取出來的主外鍵。數據庫設計
實際中關於三範式的整理函數
通過研究和對使用中問題的總結,對於設計數據庫提出了一些規範,這些規範被稱爲範式(Normal Form)性能
目前有跡可尋的共有8種範式,通常須要遵照3範式便可fetch
◆ 第一範式(1NF):強調的是列的原子性,即列不可以再分紅其餘幾列。優化
考慮這樣一個表:【聯繫人】(姓名,性別,電話) 若是在實際場景中,一個聯繫人有家庭電話和公司電話,那麼這種表結構設計就沒有達到 1NF。要符合 1NF 咱們只需把列(電話)拆分,即:【聯繫人】(姓名,性別,家庭電話,公司電話)。1NF 很好辨別,可是 2NF 和 3NF 就容易搞混淆。
◆ 第二範式(2NF):首先是 1NF,另外包含兩部份內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須徹底依賴於主鍵,而不能只依賴於主鍵的一部分。
考慮一個訂單明細表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。 由於咱們知道在一個訂單中能夠訂購多種產品,因此單單一個 OrderID 是不足以成爲主鍵的,主鍵應該是(OrderID,ProductID)。顯而易見 Discount(折扣),Quantity(數量)徹底依賴(取決)於主鍵(OderID,ProductID),而 UnitPrice,ProductName 只依賴於 ProductID。因此 OrderDetail 表不符合 2NF。不符合 2NF 的設計容易產生冗餘數據。
能夠把【OrderDetail】表拆分爲【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)來消除原訂單表中UnitPrice,ProductName屢次重複的狀況。
◆ 第三範式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的狀況。
考慮一個訂單表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主鍵是(OrderID)。 其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主鍵列都徹底依賴於主鍵(OrderID),因此符合 2NF。不過問題是 CustomerName,CustomerAddr,CustomerCity 直接依賴的是 CustomerID(非主鍵列),而不是直接依賴於主鍵,它是經過傳遞才依賴於主鍵,因此不符合 3NF。 經過拆分【Order】爲【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)從而達到 3NF。 *第二範式(2NF)和第三範式(3NF)的概念很容易混淆,區分它們的關鍵點在於,2NF:非主鍵列是否徹底依賴於主鍵,仍是依賴於主鍵的一部分;3NF:非主鍵列是直接依賴於主鍵,仍是直接依賴於非主鍵列。
E表示entry,實體,設計實體就像定義一個類同樣,指定從哪些方面描述對象,一個實體轉換爲數據庫中的一個表
R表示relationship,關係,關係描述兩個實體之間的對應規則,關係的類型包括包括一對1、一對多、多對多
關係也是一種數據,須要經過一個字段存儲在表中
實體之間會由於引用相互引用字段而存在關係,這種關係通常有三種:
1-1
1-n
n-m[ 多對多通常表現爲2個 1對多 ]
實體A對實體B爲1對1,則在表A或表B中建立一個字段,存儲另外一個表的主鍵值
實體A對實體B爲1對多:在表B中建立一個字段,存儲表A的主鍵值
實體A對實體B爲1對1,則在表A或表B中建立一個字段,存儲另外一個表的主鍵值
實體A對實體B爲1對多:在表B中建立一個字段,存儲表A的主鍵值
實體A對實體B爲多對多:新建一張表C,這個表只有兩個字段,一個用於存儲A的主鍵值,一個用於存儲B的
實體A對實體B爲多對多:新建一張表C,這個表只有兩個字段,一個用於存儲A的主鍵值,一個用於存儲B的主鍵值
對於重要數據,並不但願物理刪除,一旦刪除,數據沒法找回
刪除方案:設置isDelete的列,類型爲bit,表示邏輯刪除,默認值爲0
對於非重要數據,能夠進行物理刪除
數據的重要性,要根據實際開發決定
能夠在設計表的時候加上一個字段isdelete
在select後面列前使用distinct能夠消除重複的行
distinct的使用須要放在第一個字段的位置,針對第一個字段進行去重。
select distinct 列1,... from 表名; 例: select distinct gender from students;
例如,統計下在學生表的全部的學生班級
select distinct class from student;
判空is null
例1:查詢沒有填寫個性簽名的學生
select * from student where description is null;
例2:查詢填寫了個性簽名的學生
select * from student where description is not null;
例3:查詢填寫了身高的男生
select * from student where description is not null and sex=1;
優先級由高到低的順序爲:小括號,not,比較運算符,邏輯運算符
and比or先運算,若是同時出現並但願先算or,須要結合()使用
當查詢結果的列來源於多張表時,須要將多張錶鏈接成一個大的數據集,再選擇合適的列返回
mysql支持三種類型的鏈接查詢,分別爲:
查詢的結果爲兩個表匹配到的數據
使用內鏈接,必須保證兩個表都會對應id的數據纔會被查詢出來。
select 字段1,字段2... from 主表 inner join 從表 on 主表.主鍵=從表.外鍵
例如:查詢學生的信息[ 成績、名字、班級 ]
咱們給學生表添加一個學生信息,而後使用該學生的主鍵id來連表查詢成績、名字和班級。
insert into student (name,sex,age,class,description) values ('劉德華',1,17,406,''); select achievement,name,class from student as a inner join achievement as b on a.id=b.sid where id=101; # 上面語句因位該學生只在學生表student中有數據,而成績表中沒有數據,因此使用內鏈接,連表查詢的結果是 Empty set (0.00 sec)
一樣,若是從表有數據,而主表沒有數據,則使用內鏈接查詢同樣沒法查詢到結果。
#例如,添加一個成績記錄,是不存在學生
insert into achievement (sid,cid,achievement) values (102,10,85); select achievement,name,class from student as a inner join achievement as b on a.id=b.sid where id=102;
只要從表有數據,無論主表是否有數據,都會查詢到結果。[以從表的結果爲主]
查詢的結果爲兩個表匹配到的數據,右表特有的數據,對於左表中不存在的數據使用null填充
select 字段1,字段2... from 主表 right join 從表 on 主表.主鍵=從表.外鍵
例如,上面的成績id爲102的學生, 咱們使用右鏈接查詢。
select achievement,name,class from student as a right join achievement as b on a.id=b.sid;
只要主表有數據,無論從表是否有數據都會被查詢出來。
查詢的結果爲兩個表匹配到的數據,左表特有的數據,對於右表中不存在的數據使用null填充
select * from 表1 left join 表2 on 表1.列 = 表2.列
例如,使用左鏈接查詢學生表與成績表,查詢學生姓名及分數
select achievement,name,class from student as a left join achievement as b on a.id=b.sid; 等同於 select achievement,name,class from achievement as b right join student as a on a.id=b.sid;
總結:三種連表查詢,最經常使用的是 left join,而後inner join保證數據的一致性。右鏈接基本上都是使用左鏈接代替。
語句:
select 表.字段1,表.字段2,表.字段3..... from 主表 left join 從表1 on 主表.主鍵=從表1.外鍵 left join 從表2 on 主表.主鍵=從表2.外鍵 # 這裏和從表2鏈接的on條件看實際狀況,也會出現從表1.主鍵=從表2.外鍵的狀況 left join 從表3 on 主表.主鍵=從表3.外鍵 # 這裏能夠是(從表1或從表2).主鍵=從表2.外鍵的狀況 left join ...
多表查詢的缺點:
多表查詢的效率,性能比單表要差。
多表查詢之後,還會帶來字段多了會引發字段覆蓋的狀況、
主表student 從表1 achievement 從表2 course
name xxx name
上面三張表若是連表,則出現主表的name覆蓋從表2的name這種狀況。
上面兩個問題:
把多表查詢語句能夠替換成單表查詢語句【須要優化的狀況】
把重複的字段名,分別使用as來設置成別的名稱。
例如,查詢白楊的班級、id、年齡和課程名稱以及對應課程的成績
select a.id,a.class,a.age,c.course,b.achievement from student as a left join achievement as b on a.id=b.sid left join course as c on c.id=b.cid where a.name='白楊';
核心就是把一張表看作2張表來操做
# 建表: create table area( id smallint not null auto_increment comment '主鍵ID', name char(30) not null comment '地區名稱', pid smallint not null default 0 comment '父級地區ID', primary key (id) ) engine=innodb charset=utf8; insert into area (name,pid) values ('廣東',0),('深圳',1),('龍崗',2),('福田',2),('寶安',2);
格式
select 字段1,字段2... from 主表(當前表) as a left join 從表(當前表) as b on a.主鍵=b.外鍵
查找深圳地區的子地區,SQL代碼:
# 主表當作保存深圳的表, # 從表當作保存深圳子地區的表 select b.id,b.name from area as a left join area as b on a.id=b.pid where a.name='深圳';
在一個 select 語句中,嵌入了另一個 select 語句, 那麼被嵌入的 select 語句稱之爲子查詢語句格式:select 字段 from 表名 where 條件(另外一條查詢語句)主查詢與子查詢的關係
子查詢是嵌入到主查詢中
子查詢是輔助主查詢的,要麼充當條件,要麼充當數據源
子查詢是能夠獨立存在的語句,是一條完整的 select 語句
例如:查詢406班級大於平均年齡的學生
使用 子查詢:
查詢406班學平生均年齡
查詢大於平均年齡的學生
查詢406班級學生的平均年齡
select name,age from student where age > (select avg(age) as avg from student where class=406) and class=406;
group by 字段 having 條件;
過濾篩選,主要做用相似於where關鍵字,用於在SQL語句中進行條件判斷,過濾結果的。可是與where不一樣的地方在於having只能跟在group by 以後使用。
例如:查詢301班級大於班上平均成績的學生成績信息(name,平均分,班級)。
# 先求301班的平均成績 select avg(achievement) as achi from student as a left join achievement as b on a.id=b.sid where class=301; # 判斷301中的每一個人平均成績大於上面的到的平均成績 select name,avg(achievement) from student as a left join achievement as b on a.id=b.sid where class=301 group by name having avg(achievement) > (select avg(achievement) as achi from student as a left join achievement as b on a.id=b.sid where class=301);
select distinct 字段1,字段2.... from 表名 as 表別名 left join 從表1 on 表名.主鍵=從表1.外鍵 left join .... where .... group by ... having ... order by ... limit start,count
執行順序爲:
from 表名[包括連表]
where ....
group by ...
select distinct *
having ...
order by ...
limit start,count
實際使用中,只是語句中某些部分的組合,而不是所有
運行mysqldump命令
mysqldump –uroot –p 數據庫名 > python.sql; # 按提示輸入mysql的密碼
鏈接mysql,建立新的數據庫
退出鏈接,執行以下命令
1.第一種方式
mysql -uroot –p 新數據庫名 < python.sql # 根據提示輸入mysql密碼
2.第二種方式
mysql> create database abc; # 建立數據庫
mysql> use abc; # 使用已建立的數據庫
mysql> set names utf8; # 設置編碼
mysql> source /home/abc/abc.sql # 導入備份數據庫
倆種方式的區別
1.第一種方式能夠本地和遠程操做
2,第二種方式只能本地操做
通常使用pymysql模塊操做數據庫
import pymysql # from pymysql import * # 建立和數據庫服務器的鏈接 connection conn = pymysql.connect(host='localhost',port=3306,user='root',password='root123456', db='student',charset='utf8') # 建立遊標對象 cursor = conn.cursor() # 中間可使用遊標完成對數據庫的操做 sql = "select * from student;" # 執行sql語句的函數 返回值是該SQL語句影響的行數 count = cursor.execute(sql) print("操做影響的行數%d" % count) # print(cursor.fetchone()) # 返回值類型是元祖,表示一條記錄 # 獲取本次操做的全部數據 for line in cursor.fetchall(): print("數據是%s" % str(line)) # 關閉資源 先關遊標 cursor.close() # 再關鏈接 conn.close()
執行語句
#執行sql,更新單條數據,並返回受影響行數 result = cursor.execute("SQL語句") #插入多條,並返回受影響的函數,例如批量添加 result2 = cursor.executemany("多條數據") #獲取最新自增ID new_id = cursor.lastrowid
獲取結果
#獲取一行 result1 = cursor.fetchone() #獲取多行[參數能夠設置指定返回數量] result2 = cursor.fetchmany(整型) #獲取全部 result3 = cursor.fetchall()
操做數據
#提交,保存新建或修改的數據,若是是查詢則不須要 conn.commit() # 寫在execute()以後
ok