python數據庫-MySQL數據庫高級查詢操做(51)

1、什麼是關係?

一、分析:有這麼一組數據關於學生的數據

學號、姓名、年齡、住址、成績、學科、學科(語文、數學、英語)

咱們應該怎麼去設計儲存這些數據呢?python

二、先考慮第一範式:列不可在拆分原則

  這裏面學科包含了三個學科,因此學科拆分爲:語文學科、數學學科、英語學科,一樣的成績也要拆分爲語文成績、數學成績、英語成績。這樣既知足了第一範式,各列能夠設計爲:mysql

學號、姓名、年齡、住址、語文學科、數學學科、英語學科、語文成績、數學成績、英語成績

三、在考慮第二範式:惟一標識

  也就是說在1NF的基礎上,非Key屬性必須徹底依賴於主鍵,第二範式(2NF)要求數據庫表中的每一個實例或記錄必須能夠被惟一地區分。選取一個能區分每一個實體的屬性或屬性組,做爲實體的惟一標識。即肯定主鍵,咱們能夠選取學號爲主鍵sql

四、接着在考慮第三範式:

  確保表中各列與主鍵列直接相關,而不是間接相關。即各列與主鍵列都是一種直接依賴關係,則知足第三範式。 

  不難發如今這麼多列中,年齡、住址和成績、學科沒有直接關係,也就是說我考多少分,和年齡及住址都無關,他們都是學生的信息,但都是不相關的信息,因此根據第三範式,咱們須要將這些數據根據其相關性拆分爲多個表。數據庫

五、表與表之間的關係

  若是咱們要想找到張三的語文成績,那麼咱們就必須去成績表中查找,由於成績表中保存的全部人的全部學科成績。可是在成績表中查找的時候,須要從省標中查到張三的學號(stu_id)和從學科表中查到語文學科(sub_id)的編號,這個時候這三張表就發生了關係,這也就是關係型數據庫的精髓,而根據這種表與表之間的關係也會衍生出不少的查詢的高級操做函數

 

2、外鍵(foreign key)

外鍵約束:用於限制主表與從表數據完整性。ui

alter table scores  add constraint 'stu_score_fk' foreign key(stu_id) references students(stu_id);
  • 將scores表的stu_id外鍵關聯到students表的stu_id字段(說明:這裏scores表裏面字段stu_id和students表裏的stu_id重名了,最好避免重名)
  • 每一個外鍵都有一個名字,能夠經過constraint指定
  • 存在外鍵的表,稱之爲從表(子表),外鍵指向的表,稱之爲主表(父表)。
  • 做用:保持數據一致性,完整性,主要目的是控制存儲在外鍵表(從表)中的數據。例如,此時在從表插入或者修改數據時,若是stu_id的值在students表中不存在則會報錯
  • 外鍵也能夠在建立表時能夠直接建立約束

語法:spa

 foreign key (外鍵字段) references 主表名 (關聯字段)
例如:
create table scores(
id int primary key auto_increment,
stu_id int,
sub_id int,
score decimal(5,2),
foreign key(stuid) references students(id),
foreign key(subid) references subjects(id)
);

[主表記錄刪除時的動做] [主表記錄更新時的動做],此時須要檢測一個從表的外鍵須要約束爲主表的已存在的值。外鍵在沒有關聯的狀況下,能夠設置爲null.前提是該外鍵列,沒有not null。

設計

3、外鍵的級聯操做

  • 在刪除或者修改students表的數據時,若是這個stu_id值在scores中已經存在,則會拋異常
  • 推薦使用邏輯刪除,還能夠解決這個問題
  • 能夠建立表時指定級聯操做,也能夠在建立表後再修改外鍵的級聯操做
alter table scores add constraint stu_sco foreign key(stu_id) references students(stu_id) on delete cascade;

除了on delete還有on update都要注意級聯操做版本控制

級聯操做的類型包括:rest

  • restrict(限制):默認值,拋異常,拒絕父表刪除或者更新
  • cascade(級聯):若是主表的記錄刪掉,則從表中相關聯的記錄都將被刪除,若是主表修改記錄,則從表記錄也將被修改
  • set null:將外鍵設置爲空
  • no action:什麼都不作

 

4、連接查詢

在講解第一個問題關係的時候,咱們提到了,若是要查找張三的語文成績,須要用到三個表,當咱們查詢結果來源於多張表的時候就須要使用鏈接查詢

連接查詢關鍵:找到表間的關係,當前的關係是

  • students表的stu_id---scores表的stu_id
  • subjects表的sub_id---scores表的sub_id

select students.stu_name,subjects.sub_name,scores.score 
from scores
inner join students on scores.stu_id=students.stu_id 
inner join subjects on scores.sub_id=subjects.sub_id 
where students.stu_name='張三' and subjects.sub_name='語文';
+----------+----------+-------+
| stu_name | sub_name | score |
+----------+----------+-------+
| 張三      | 語文     |    80 |
+----------+----------+-------+
  • 結論:當須要對有關係的多張表進行查詢時,須要使用鏈接join
  • 鏈接查詢分類以下:
    • 表A inner join 表B:表A與表B匹配的行會出如今結果中
    • 表A left join 表B:表A與表B匹配的行會出如今結果中,外加表A中獨有的數據,未對應的數據使用null填充
    • 表A right join 表B:表A與表B匹配的行會出如今結果中,外加表B中獨有的數據,未對應的數據使用null填充
    • 在查詢或條件中推薦使用「表名.列名」的語法
    • 若是多個表中列名不重複能夠省略「表名.」部分
    • 若是表的名稱太長,能夠在表名後面使用' as 簡寫名'或' 簡寫名',爲表起個臨時的簡寫名稱

 

5、視圖

  視圖就像咱們python裏面的函數同樣,對SQL語言代碼塊的封裝

    • 對於複雜的查詢,在屢次使用後,維護是一件很是麻煩的事情
    • 解決:定義視圖
    • 視圖本質就是對查詢的一個封裝
    • 定義視圖
create view stuscore as select students.stu_name,subjects.sub_name,scores.score from scores inner join students on scores.stu_id=students.stu_id inner join subjects on scores.sub_id=subjects.sub_id;

這句話的意思就是用stuscore就至關於後面紅色很長的一段SQL語句:

mysql> select *from stuscore;
+----------+----------+-------+
| stu_name | sub_name | score |
+----------+----------+-------+
| 張三     | 語文     |    80 |
| 張三     | 數學     |    85 |
| 張三     | 英語     |    88 |
| 李四     | 語文     |    83 |
| 李四     | 數學     |    84 |
| 李四     | 英語     |    87 |
| 王五     | 語文     |    81 |
| 王五     | 數學     |    85 |
| 王五     | 英語     |    85 |
| 趙六     | 語文     |    88 |
| 趙六     | 數學     |    88 |
| 趙六     | 英語     |    87 |
| 侯七     | 語文     |    84 |
| 侯七     | 數學     |    83 |
| 侯七     | 英語     |    82 |
+----------+----------+-------+

 

 6、自鏈接查詢

  有時在信息查詢時須要進行對自身鏈接(自鏈接)自鏈接是單邊操做,因此咱們須要爲表定義別名。舉例說明,下面是一個新的學生成績表,在下表中咱們要找到比張三成績高的。

+--------+----------+-----------+
| stu_id | stu_name | stu_score |
+--------+----------+-----------+
|      1 | 張三     |        90 |
|      2 | 李四     |        85 |
|      3 | 王五     |        80 |
|      4 | 趙六     |        95 |
|      5 | 侯七     |       100 |
+--------+----------+-----------+

  通常狀況咱們看到這張表咱們第一時間用語句進行操做:

select * from Score where stu_score>90;

  可想而知,這是有多麼簡單,假設你並不知道數據庫中張三的成績是90或者數據量至關龐大呢?做爲一個數據庫管理員,咱們就要用別的方式迅速找出所須要的數據。

 

方式一:分步查找:最簡單的一種方式,也是最容易想到的操做「

select stu_score from Score where stu_name='張三';//得出張三的成績
select *from Score where stu_score>90;

  與採用自鏈接的方式相比,這種方法須要對中間結果進行人工干預,顯然不利於程序中的自動處理操做。

方式二:自鏈接方式:

select * from Score as a,Score as b where a.stu_name='張三' and a.stu_score<b.stu_score;
+--------+----------+-----------+--------+----------+-----------+
| stu_id | stu_name | stu_score | stu_id | stu_name | stu_score |
+--------+----------+-----------+--------+----------+-----------+
|      1 | 張三      |        90 |      4 | 趙六     |        95 |
|      1 | 張三      |        90 |      5 | 侯七     |       100 |
+--------+----------+-----------+--------+----------+-----------+

若是不想把張三的信息打印出來咱們能夠調整SQL語句爲:

select b.* from Stu_score as a,Stu_score as b where a.stu_name='張三' and a.stu_score<b.stu_score;
+--------+----------+-----------+
| stu_id | stu_name | stu_score |
+--------+----------+-----------+
|      4 | 趙六      |        95 |
|      5 | 侯七      |       100 |
+--------+----------+-----------+

注意:別名 a,b雖然名稱不一樣,可是同一個表,定義別名的目的是更方便在自身進行刪選。
執行select經過(中間表)所獲得的b.*,,就是最終結果。

 

7、子查詢

子查詢也是經常使用的一種方式,就是在select裏嵌套select。仍是上面的例子,咱們用子查詢實現以下:

select * from Stu_score where stu_score>(select stu_score from Stu_score where stu_name='張三'); 
+--------+----------+-----------+
| stu_id | stu_name | stu_score |
+--------+----------+-----------+
|      4 | 趙六      |        95 |
|      5 | 侯七      |       100 |
+--------+----------+-----------+

 

8、內置函數

一、字符串函數

一、查看字符的ascii碼值ascii(str),str是空串時返回0

mysql> select ascii('a'); +------------+
| ascii('a') |
+------------+
|         97 |
+------------+

二、查看ascii碼值對應的字符char(數字)

mysql> select char(97); +----------+
| char(97) |
+----------+
| a        |
+----------+

三、拼接字符串concat(str1,str2...)

select concat(12,34,'ab'); +--------------------+
| concat(12,34,'ab') |
+--------------------+
| 1234ab             |
+--------------------+

四、包含字符個數length(str)

mysql> select length('abc'); +---------------+
| length('abc') |
+---------------+
|             3 |
+---------------+

五、截取字符串

  • left(str,len)返回字符串str的左端len個字符
  • right(str,len)返回字符串str的右端len個字符
  • substring(str,pos,len)返回字符串str的位置pos起len個字符
mysql> select substring('abc123',2,3); +-------------------------+
| substring('abc123',2,3) |
+-------------------------+
| bc1                     |
+-------------------------+

六、去除空格

  • ltrim(str)返回刪除了左空格的字符串str
  • rtrim(str)返回刪除了右空格的字符串str
  • trim([方向 remstr from str)返回從某側刪除remstr後的字符串str,方向詞包括both、leading、trailing,表示兩側、左、右
mysql> select trim(' bar '); +------------------+
| trim('  bar   ') |
+------------------+
| bar              |
+------------------+
mysql> select trim(leading 'x' FROM 'xxxbarxxx'); +------------------------------------+
| trim(leading 'x' FROM 'xxxbarxxx') |
+------------------------------------+
| barxxx                             |
+------------------------------------+
mysql> select trim(trailing 'x' FROM 'xxxbarxxx'); +-------------------------------------+
| trim(trailing 'x' FROM 'xxxbarxxx') |
+-------------------------------------+
| xxxbar                              |
+-------------------------------------+
mysql> select trim(both 'x' FROM 'xxxbarxxx'); +---------------------------------+
| trim(both 'x' FROM 'xxxbarxxx') |
+---------------------------------+
| bar                             |
+---------------------------------+

七、替換字符串replace(str,from_str,to_str)

mysql> select replace('abc123','123','def');
+-------------------------------+
| replace('abc123','123','def') |
+-------------------------------+
| abcdef                        |
+-------------------------------+

八、大小寫轉換,函數以下

  • lower(str)
  • upper(str)
mysql> select lower('aBcD');
+---------------+
| lower('aBcD') |
+---------------+
| abcd          |
+---------------+

二、數學函數

一、求絕對值abs(n)

mysql> select abs(-32);
+----------+
| abs(-32) |
+----------+
|       32 |
+----------+

二、求m除以n的餘數mod(m,n),同運算符%

mysql> select mod(10,3);
+-----------+
| mod(10,3) |
+-----------+
|         1 |
+-----------+

mysql> select 10%3;
+------+
| 10%3 |
+------+
|    1 |
+------+

三、floor(n),表示不大於n的最大整數

mysql> select floor(2.3);
+------------+
| floor(2.3) |
+------------+
|          2 |
+------------+

四、ceiling(n),表示不小於n的最大整數

mysql> select ceiling(2.3);
+--------------+
| ceiling(2.3) |
+--------------+
|            3 |
+--------------+

五、求四捨五入值round(n,d),n表示原數,d表示小數位置,默認爲0

mysql> select round(1.6);
+------------+
| round(1.6) |
+------------+
|          2 |
+------------+

六、求x的y次冪pow(x,y)

mysql> select pow(2,3);
+----------+
| pow(2,3) |
+----------+
|        8 |
+----------+

七、隨機數rand(),值爲0-1.0的浮點數

mysql> select rand();
+--------------------+
| rand()             |
+--------------------+
| 0.0713081630610937 |
+--------------------+

三、日期時間函數

  • 獲取子值,語法以下
    • year(date)返回date的年份(範圍在1000到9999)
    • month(date)返回date中的月份數值
    • day(date)返回date中的日期數值
    • hour(time)返回time的小時數(範圍是0到23)
    • minute(time)返回time的分鐘數(範圍是0到59)
    • second(time)返回time的秒數(範圍是0到59)
mysql> select year('2019-7-11');
+-------------------+
| year('2019-7-11') |
+-------------------+
|              2019 |
+-------------------+
  • 日期計算,使用+-運算符,數字後面的關鍵字爲year、month、day、hour、minute、second
mysql> select '2019-7-11'+interval 1 day;
+----------------------------+
| '2019-7-11'+interval 1 day |
+----------------------------+
| 2019-07-12                 |
+----------------------------+

日期格式化date_format(date,format),format參數可用的值以下

  • 獲取年%Y,返回4位的整數

    * 獲取年%y,返回2位的整數

    * 獲取月%m,值爲1-12的整數

  • 獲取日%d,返回整數

    * 獲取時%H,值爲0-23的整數

    * 獲取時%h,值爲1-12的整數

    * 獲取分%i,值爲0-59的整數

    * 獲取秒%s,值爲0-59的整數

 

9、事物

  • 當一個業務邏輯須要多個sql語句完成時,若是其中某條sql語句出錯,則但願整個操做都退回
  • 使用事務能夠完成退回的功能,保證業務邏輯的正確性
  • 事務四大特性(簡稱ACID)
    • 原子性(Atomicity):事務中的所有操做在數據庫中是不可分割的,要麼所有完成,要麼均不執行
    • 一致性(Consistency):幾個並行執行的事務,其執行結果必須與按某一順序串行執行的結果相一致
    • 隔離性(Isolation):事務的執行不受其餘事務的干擾,事務執行的中間結果對其餘事務必須是透明的
    • 持久性(Durability):對於任意已提交事務,系統必須保證該事務對數據庫的改變不被丟失,即便數據庫出現故障
  • 要求:表的類型必須是innodb或bdb類型,才能夠對此表使用事務
  • 查看錶的建立語句
show create table Stu_score;
  • 修改表的類型:alter table '表名' engine=innodb;
alter table Stu_score engine=innodb;
  • 事務語句
開啓begin;
提交commit;
回滾rollback;

  在begin;後面寫咱們要操做的SQL語句組合也就是咱們所謂的要執行的事物,可是這個時候寫好的SQL語句就算咱們回車以後,也不會執行,知道commit;執行以後纔會被執行到數據庫中,rollback回滾是咱們begin;以後發現咱們寫錯了,或者不想執行了,均可以在commit;以前回滾到上一次commit;的狀態,很像版本控制器SVN和GIT同樣

相關文章
相關標籤/搜索