DDL(DataDefinitionLanguage),也就是數據定義語言,它用來定義咱們的數據庫對象,包括 數據庫、數據表和列。經過使用DDL,能夠建立,刪除和修改數據庫和表結構。html
CREATE DATABASE nba; // 建立一個名爲nba的數據庫 DROP DATABASE nba; // 刪除一個名爲nba的數據庫
CREATE TABLE table_name
建立表結構mysql
CREATE TABLE player ( player_id int(11) NOT NULL AUTO_INCREMENT, player_name varchar(255) NOT NULL );
修改表結構sql
// 修改字段 ALTER TABLE player ADD (age int(11)); // 修改字段名 ALTER TABLE player RENAME COLUMN age to player_age // 修改字段的數據庫類型 ALTER TABLE player MODIFY (player_age float(3,1)); // 刪除字段 ALTER TABLE player DROP COLUMN player_age;
數據標的常見約束數據庫
目的:express
保證RDBMS裏面數據的準確性和一致性。編程
常見的約束:緩存
咱們常經過可視化管理和設計工具進行數據庫的設計。例如:Navicat安全
DML(DataManipulationLanguage),數據操做語言,咱們用它操做和數據庫相關的記錄,比 如增長、刪除、修改數據表中的記錄。服務器
DCL(DataControlLanguage),數據控制語言,咱們用它來定義訪問權限和安全級別。網絡
DQL(DataQueryLanguage),數據查詢語言,咱們用它查詢想要的記錄。
DB(DataBase),也就是數據庫。
DBS(DataBase System),也就是數據庫系統。它是更大的概念,包括了數據庫、數據庫管理系統以及數據庫管理人員DBA。
DBMS(DataBase Management System),也就是數據庫管理系統。DBMS = 多個數據庫(DB) + 管理程序。
日常咱們說的Oracle、MySQL等稱之爲數據庫,但確切講,它們應該是數據庫管理系統,即DBMS。
關係型數據庫(RDBMS)和非關係型數據庫(NoSQL)
關係型數據庫就是創建在關係模型基礎上的數據庫,SQL就是關係數據庫的查詢語言。
非關係數據庫分類不少,主要有如下這些:
Oracle經過檢查共享池是否存在SQL語句的執行計劃,來判斷進行軟解析,仍是硬解析。
如何理解軟解析和硬解析?
在共享池中,Oracle首先對SQL語句進行Hash運算,而後根據Hash值在庫緩存(Library Cache)中查 找,若是存在SQL語句的執行計劃,就直接拿來執行,直接進入「執行器」的環節,這就是軟解析。
若是沒有找到SQL語句和執行計劃,Oracle就須要建立解析樹進行解析,生成執行計劃,進入「優化 器」這個步驟,這就是硬解析。
共享池是Oracle中的術語,包括了庫緩存,數據字典緩衝區等。
如何避免硬解析,儘可能使用軟解析?
在Oracle中,綁定變量是它的一大特點。綁定變量就是在SQL語句中使用變量,經過不一樣的變量取值來改變SQL的執行結果。這樣作的好處是能提高軟解析的可能性,不足之處在於可能會致使生成的執行計劃不夠優化,所以是否須要綁定變量還須要視狀況而定。
MySQL是典型的C/S架構,即Client/Server架構,服務器端程序使用的mysqld。總體的MySQL流程以下圖所示:
MySQL由三層組成:
其中,SQL層與數據庫文件的存儲方式無關,SQL層結構以下:
1. 查詢緩存: Server若是在查詢緩存中發現了這條SQL語句,就會直接將結果返回給客戶端;若是沒有,就進入到解析器階段。須要說明的是,由於查詢緩存每每效率不高,因此在My拼SQ課L8.0以後就拋棄了這個功能。
2. 解析器: 在解析器中對SQL語句進行語法分析、語義分析。
3. 優化器: 在優化器中會肯定SQL語句的執行路徑,好比是根據全表檢索,仍是根據索引來檢索等。
4. 執行器: 在執行以前須要判斷該用戶是否具有權限,若是具有權限就執行SQL查詢並返回結果。在
MySQL8.0如下的版本,若是設置了查詢緩存,這時會將查詢結果進行緩存。
這部分與Oracle執行SQL的原理是同樣的。
與Oracle不一樣的是,MySQL的存儲引擎採用了插件的形式,每一個存儲引擎都面向一種特定的數據庫應用環境。同時開源的MySQL還容許開發人員設置本身的存儲引擎,下面是一些常見的存儲引擎:
「三少一多」
通常在生產環境下,不推薦直接使用SELECT*進行查詢。(由於效率不高)
// 查詢列 colmns代指須要查詢列(* 查詢所有,但在生產環境中較少使用,影響效率); tablename爲表名 SELECT columns FROM tablename // 起別名 SELECT name AS n, hp_max AS hm // 查詢常數 SELECT '王者榮耀' AS platfor, name FROM heros // 去除重複行 // DISTINCT須要放到全部列名的前面; DISTINCT實際上是對後面全部列名的組合進行去重 SELECT DISTINCT attack_range FROM heros // 如何排序檢索數據( ORDER BY 子句 默認按ASC遞增排序) // ORDER BY 一般位於 SELECT 語句的最後一條子句 SELECT name, hp_max FROM heros ORDER BY mp_max, hp_max DESC // 約束返回結果的數量 LIMIT // 約束返回結果的數量能夠減小數據表的網絡傳輸量,也能夠提高查詢效率。 SELECT name, hp_max FROM heros, ORDER BY hp_max DESC LIMIT 5
SELECT...FROM...WHERE...GROUP BY...HAVING...ORDER BY...
FROM > WHERE > GROUP BY > HAVING > SELCT的字段 > DISTINCT > ORDER BY > LIMIT
// 例如一個SQL語句,執行順序以下: SELECT DISTINCT palyer_id, player_name, count(*) as num #順序5 FROM player JOIN team ON player.team_id = team.team_id #順序1 WHERE height > 1.80 #順序2 GROUP BY player.team_id #順序3 HAVING num > 2 #順序4 ORDER BY num DESC #順序6 LIMIT 2 #順序7
在SELECT語句執行這些步驟的時候,每一個步驟都會產生一個虛擬表,而後將這個虛擬表傳入下一個步驟中做爲輸入。
SQL語句的SELECT是先執行FROM這一步的。在這個階段,若是是多張表聯查,還會經歷下面的幾個步驟:
若是操做的是兩張以上的表,還會重複上面的步驟,直到全部表都被處理完爲止。這個過程獲得是原始數據,也就是最終的虛擬表vt1,就能夠在這個基礎上再進行WHERE階段。在這個階段中,會根據vt1表的結果進行篩選過濾,獲得虛擬表vt2。
而後進入第三步和第四步,也就是GROUP和HAVING階段。在這個階段中,其實是在虛擬表vt2的基礎上進行分組和分組過濾,獲得中間的虛擬表vt3和vt4。
完成條件篩選部分後,就能夠篩選表中提取的字段,也就是進入到SELECT和DISTINCT階段。
首先在SELECT階段會提取想要的字段,而後在DISTINCT階段過濾重複的行,分別獲得中間的虛擬表vt5-1和vt5-2。
當提取了想要的字段後,就能夠按照指定的字段進行排序,也就是ORDER BY階段,獲得虛擬表vt6。
最後在vt6的基礎上,取出指定行的記錄,也就是LIMIT階段,獲得最終的結果,對應的是虛擬表vt7。
子查詢既嵌套在查詢中的查詢,有便於咱們進行更復雜的查詢。
它劃分爲關聯子查詢和非關聯子查詢。
子查詢須要執行屢次,採用循環的方式,先從外部查詢開始,每次都傳入子查詢進行查詢,而後再將結果反饋給外部,這種嵌套的執行方式就稱爲關聯子查詢。
SELECT player_name, height, team_id FROM player AS a WHERE height > (SELECT avg(height) FROM player AS b WHERE a.team_id = b.team_id
子查詢從數據表中查詢了數據結果,若是這個數據結果只執行一次,而後這個數據結果做爲主查詢的條件進行執行,那麼這樣的子查詢叫作非關聯子查詢。
SELECT player_name, height FROM player WHERE height = (SELECT max(height) FROM player)
EXISTS子查詢
關聯子查詢一般也會和EXISTS子查詢一塊兒使用。EXISTS子查詢用來判斷條件是否知足,知足爲True,不知足爲False。
集合比較子查詢(IN、ANY、ALL、SOME)
IN:判斷是否在集合中
ANY:須要與比較操做符一塊兒使用,與子查詢返回的任何值作比較
ALL:須要與比較操做符一塊兒使用,與子查詢返回的任何值作比較
SOME:其實是ANY的別名,做用相同,通常常使用ANY
把子查詢的結果做爲主查詢的列
SQL存在不一樣版本的標準規範,由於不一樣規範下的錶鏈接操做是有區別的。其有兩個主要的標準,分別是SQL92和SQL99。
SQL92的5種鏈接方式,它們分別是笛卡爾積、等值鏈接、非等值鏈接、外鏈接(左鏈接、右鏈接)和自鏈接。
笛卡爾積(交叉鏈接)CROSS JOIN
笛卡爾積是一個數學運算。假設兩個集合X和Y,X和Y的笛卡爾積就是X和Y的全部可能組合。
它的做用就是能夠把任何表進行鏈接,即便這兩張表不相關。
等值鏈接
兩張表的等值鏈接就是用兩張表中都存在的列進行鏈接。也能夠對多張表進行等值鏈接。
非等值鏈接
進行多表查詢的時候,若是鏈接多個表的條件是等號時,就是等值鏈接,其餘的運算符鏈接就是非等值查詢。
外鏈接
兩張表的外鏈接,會有一張主表,另外一張是從表。若是是多張表的外鏈接,那麼第一張表是主表,即顯示所有的行,而剩下的表則顯示對應鏈接的信息。
在SQL92中才用(+)表明從表所在的位置,其只有左外鏈接和右外鏈接,沒有全外鏈接。
左外鏈接:
指左邊的表是主表,須要顯示左邊表的所有行,而右側的表是從表,(+)表示哪一個是從表。
右外鏈接:
指的是右邊的表是主表,須要顯示右邊表的所有行,而左側的是從表。
自鏈接
自鏈接能夠對多個表進行操做,也能夠對同一個表進行操做。也就是說查詢條件使用了當前表的字段。
交叉鏈接
即SQL92中的笛卡爾乘積,這裏採用的是CROSS JOIN。
天然鏈接
即SQL92的等值鏈接。這裏採用的是NATURAL JOIN。
// SQL92 SELECT player_id, a.team_id, player_name, height, team_name FROM player as a, team as b WHERE a.team_id = b.team_id // SQL99 SELECT player_id, team_id, player_name, height, team_name FROM player NATURAL JOIN team
ON鏈接
ON鏈接用來指定想要的鏈接條件。
通常來講在SQL99中,須要鏈接的表會採用JOIN進行鏈接,ON指定了鏈接條件,後面能夠是等值鏈接,也能夠採用非等值鏈接。
USING鏈接
使用USING指定數據表裏同名字段進行等值鏈接。使用JOIN USING能夠簡化JOIN ON的等值鏈接。例如:
// JOIN ON SELECT player_id, player.team_id, player_name, height, team_name FROM player JOIN team ON player.team_id = team.team_id // JOIN USING SELECT player_id, team_id, player_name, height, team_name FROM player JOIN team USING(team_id)
外鏈接
SQL99的外鏈接包括三種形式:
MySQL不支持全外鏈接,不然的話全外鏈接會返回左表和右表中的全部行。
全外鏈接的結果 = 左右表匹配的數據 + 左表沒有匹配到的數據 + 右表沒有匹配到的數九
自鏈接
自鏈接的原理在SQL92和SQL99中都是同樣的,只是表述方式不一樣。
在SQL92中進行查詢時,會把全部須要鏈接的表都放到FROM以後,而後在WHERE中寫明鏈接的條件。
而在SQL99中這方面更靈活,它不須要一次性把全部須要鏈接的表都放到FROM以後,而是採用JOIN的方式,每次鏈接一張表,能夠屢次使用JOIN進行鏈接。
SELECT ... FROM table1 JOIN table2 ON table1和table2的鏈接條件 JOIN table3 ON table2和table3的鏈接條件
多表鏈接建議使用SQL99標準,由於層次性更強,可讀性更強
視圖即虛擬表,它至關因而一張表或多張表的數據結果集。
一般狀況下,小型項目的數據庫能夠不使用視圖,可是在大型項目中,以及數據表比較複製的狀況下,視圖的價值就凸顯出來了,它能夠幫助咱們把常常查詢的結果集放到虛擬表中,提高使用效率。
// 語法 CREATE VIEW view_name AS SELECT column1, column2 FROM table WHERE condition // 實例 CREATE VIEW player_above_avg_height AS SELECT player_id, height FROM player WHERE height > (SELECT AVG(height) from player)
CREATE VIEW player_above_above_avg_height AS SELECT player_id, height FROM player WHERE height > (SELECT AVG(height) from player_above_avg_height)
ALTER VIEW view_name AS SELECT column1, column2 FROM table WHERE condition
DROP VIEW view_name
存儲過程(Stored Procedure)是程序化的SQL,能夠直接操做底層數據表,相比於面向集合的操做方式,可以實現一些更復雜的數據處理。它由SQL語句和流控制語句共同組成。
CREATE PROCEDURE 存儲過程名稱([參數列表]) BEGIN 須要執行的語句 END
與視圖類型,刪除存儲過程使用的是DROP PROCEDURE;更新存儲過程爲ALTER PROCEDURE。
下面看一個簡單的例子:
// 1+2+...+n CREATE PROCEDURE `add_num`(IN n INT) BEGIN DECLARE i INT; DECLARE sum INT; SET i = 1; SET sum = 0; WHILE i <= n DO SET sum = sum + i; SET i = i + 1; END WHILE; SELECT sum; END
若是須要再次使用這個存儲過程時,直接使用CALL add_num(50);便可。
參數類型 |
是否返回 |
做用 |
IN |
否 |
向存儲過程傳入參數,存儲過程當中修改該參數的值,不能被返回。 |
OUT |
是 |
把存儲過程計算的結果放到該參數中,調用者能夠獲得返回值。 |
INOUT |
是 |
IN和OUT的結合,既用於存儲過程的傳入參數,同時又能夠把計算結果放到參數中,調用者能夠獲得返回值 |
IN和OUT的結合,既用於存儲過程的傳入參數,同時又能夠把計算機結果放到參數中,調用者能夠獲得返回值。
IN參數必須在調用過程時指定,而在存儲過程當中修改該參數的值不能被返回。而OUT參數和INOUT參數能夠在存儲過程當中被改變,並可返回。
例如以下:
// 查詢某一類型英雄中的最大的最大生命值,最小的最大魔法值,以及平均最大攻擊值 CREATE PROCEDURE `get_hero_scores`( OUT max_max_hp FLOAT, OUT min_max_mp FLOAT, OUT avg_max_attack FLOAT, s VARCHAR(255) ) BEGIN SELECT MAX(hp_max), MIN(mp_max), AVG(attack_max) FROM heros WHERE role_main = s INTO max_max_hp, min_max_mp, avg_max_attack END // 進行調用 CALL get_hero_scores(@max_max_hp, @min_max_mp, @avg_max_attack, '戰士'); SELECT @max_max_hp, @min_max_mp, @avg_max_attack;
其中間包含了多個語句,每一個語句都以(;)號爲結束符。
用於聲明變量,使用的位置在於BEGIN...END語句中間,並且須要在其餘語句以前進行變量的聲明。
賦值語句,用於對變量進行賦值。
把從數據表中查詢的結果存放到變量中,也就是爲變量賦值。
條件判斷語句,咱們還能夠在iF...THEN...ENDIF中使用ELSE和ELSEIF來進行條件判斷。
用於多條件的分支判斷,語法以下:
CASE WHEN expression1 THEN ... WHEN expression2 THEN ... ... ELSE --ELSE可加可不加。加的話表明全部條件都不知足時採用的方式 END
LOOP是循環語句,使用LEAVE能夠跳出循環,使用ITERATE則能夠進入下一 次循環。若是你有面向過程的編程語言的使用經驗,你能夠把LEAVE理解爲BREAK,把ITERATE理解爲 CONTINUE。
這是一個循環語句,首先會執行一次循環,而後在UNTIL中進行表達式 的判斷,若是知足條件就退出,即END REPEAT;若是條件不知足,則會就繼續執行循環,直到知足退出條 件爲止。
這也是循環語句,和REPEAT循環不一樣的是,這個語句須要先進行條件判斷, 若是知足條件就進行循環,若是不知足條件就1退出循環。
有些公司對於大型項目要求使用存儲過程,而有些則在手冊中明確禁止使用存儲過程。
保證了一次處理的完整性,也保證了數據庫中的數據一致性。
ACID是事務的四大特性。原子性是基礎,隔離性是手段,一致性是約束條件,而持久性使咱們的目的。
使用事務有兩種方式,分爲隱式事務和顯式事務。隱式事務實際上就是自動提交,Oracle默認不自動提交,須要手動COMMIT命令,而MySQL默認自動提交。
共有3種異常狀況:髒讀(Dirty Read)、不可重複讀和幻讀(Phantom Read)
|
髒讀 |
不可重複讀 |
幻讀 |
讀未提交(READ UNCOMMITTED) |
容許 |
容許 |
容許 |
讀已提交(READ COMMITTED) |
禁止 |
容許 |
容許 |
可重複讀(REPEATABLE READ) |
禁止 |
禁止 |
容許 |
可串行化(SERIALIZABLE) |
禁止 |
禁止 |
禁止 |
讀未提交,也就是容許讀到未提交的數據,這種狀況下查詢是不會使用鎖的,可能會產生髒讀、不可重複 讀、幻讀等狀況。
讀已提交就是隻能讀到已經提交的內容,能夠避免髒讀的產生,屬於RDBMS中常⻅的默認隔離級別(好比說Oracle和SQL Server),但若是想要避免不可重複讀或者幻讀,就須要咱們在SQL查詢的時候編寫帶加鎖 的SQL語句(我會在進階篇裏講加鎖)。
可重複讀,保證一個事務在相同查詢條件下兩次查詢獲得的數據結果是一致的,能夠避免不可重複讀和髒讀,但沒法避免幻讀。MySQL默認的隔離級別就是可重複讀。
可串行化,將事務進行串行化,也就是在一個隊列中按照順序執行,可串行化是最高級別的隔離等級,能夠解決事務讀取中全部可能出現的異常狀況,可是它犧牲了系統的併發性。
遊標,一種靈活的操做方式,可讓咱們從數據結果集中每次提取一條數據記錄進行操做。
在SQL中,遊標是一種臨時的數據庫對象,能夠指向存儲在數據庫表中的數據行指針。這裏遊標充當了指針的做用,能夠經過操做遊標來對數據行進行操做。
通常須要經歷五個步驟。不一樣DBMS中,使用遊標的語法可能略有不一樣。
一、定義遊標
// 適用於MySQL,SQL Server,DB2和MariaDB DECLARE cursor_name CURSOR FOR select_statement // Oracle / PostgreSQL DECLARE cursor_name CURSOR IS select_statement
二、打開遊標
OPEN cursor_name
三、從遊標中取得數據
FETCH cursor_name INTO var_name ...
這句話的做用是使用cursor_name這個遊標來讀取當前行,而且將數據保存到var_name這個變量中,遊標指針指到下一行。若是遊標讀取的數據行有多個列明,則在INTO關鍵字後面賦值多個變量名便可。
四、關閉遊標
CLOSE cursor_name
五、釋放遊標
DEALLOCATE PREPARE
假設想用遊標掃描heros數據表中的數據行,而後累計最大生命值。
CREATE PROCEDURE `calc_hp_max`() BEGIN -- 建立接收遊標的變量 DECLARE hp INT; -- 建立總數變量 DECLARE hp_sum INT DEFAULT 0; -- 建立結束標誌變量 DECLARE done INT DEFAULT false; -- 定義遊標 DECLARE cur_hero CURSOR SELECT hp_max FROM heros; OPEN cur_hero; read_loop:LOOP FETCH cur_hero INTO hp; -- 判斷遊標的訓話是否結束 IF done THEN LEAVE read_loop; END IF SET hp_sum = hp_sum + hp; END LOOP; CLOSE cur_hero SELECT hp_sum; DEALLOCATE PREPARE cur_hero; END