做者:靜默虛空
原文:https://juejin.im/post/5c7e52...mysql
本文針對關係型數據庫的通常語法。限於篇幅,本文側重說明用法,不會展開講解特性、原理。sql
數據庫(database)
- 保存有組織的數據的容器(一般是一個文件或一組文件)。數據表(table)
- 某種特定類型數據的結構化清單。模式(schema)
- 關於數據庫和表的佈局及特性的信息。模式定義了數據在表中如何存儲,包含存儲什麼樣的數據,數據如何分解,各部分信息如何命名等信息。數據庫和表都有模式。列(column)
- 表中的一個字段。全部表都是由一個或多個列組成的。行(row)
- 表中的一個記錄。主鍵(primary key)
- 一列(或一組列),其值可以惟一標識表中每一行。SQL(Structured Query Language),標準 SQL 由 ANSI 標準委員會管理,從而稱爲 ANSI SQL。各個 DBMS 都有本身的實現,如 PL/SQL、Transact-SQL 等。
SQL 語法結構包括:數據庫
子句
- 是語句和查詢的組成成分。(在某些狀況下,這些都是可選的。)表達式
- 能夠產生任何標量值,或由列和行的數據庫表謂詞
- 給須要評估的 SQL 三值邏輯(3VL)(true/false/unknown)或布爾真值指定條件,並限制語句和查詢的效果,或改變程序流程。查詢
- 基於特定條件檢索數據。這是 SQL 的一個重要組成部分。語句
- 能夠持久地影響綱要和數據,也能夠控制數據庫事務、程序流程、鏈接、會話或診斷。例如:SELECT
與 select
、Select
是相同的。編程
;
)分隔。-- 一行 SQL 語句 UPDATE user SET username='robot', password='robot' WHERE username = 'root'; -- 多行 SQL 語句 UPDATE user SET username='robot', password='robot' WHERE username = 'root';
## 註釋1 -- 註釋2 /* 註釋3 */
數據定義語言(Data Definition Language,DDL)是 SQL 語言集中負責數據結構定義與數據庫對象定義的語言。segmentfault
DDL 的主要功能是定義數據庫對象。安全
DDL 的核心指令是 CREATE
、ALTER
、DROP
。服務器
數據操縱語言(Data Manipulation Language, DML)是用於數據庫操做,對數據庫其中的對象和數據運行訪問工做的編程語句。數據結構
DML 的主要功能是 訪問數據,所以其語法都是以讀寫數據庫爲主。app
DML 的核心指令是 INSERT
、UPDATE
、DELETE
、SELECT
。這四個指令合稱 CRUD(Create, Read, Update, Delete),即增刪改查。函數
事務控制語言 (Transaction Control Language, TCL) 用於管理數據庫中的事務。這些用於管理由 DML 語句所作的更改。它還容許將語句分組爲邏輯事務。
TCL 的核心指令是 COMMIT
、ROLLBACK
。
數據控制語言 (Data Control Language, DCL) 是一種可對數據訪問權進行控制的指令,它能夠控制特定用戶帳戶對數據表、查看錶、預存程序、用戶自定義函數等數據庫對象的控制權。
DCL 的核心指令是 GRANT
、REVOKE
。
DCL 以控制用戶的訪問權限爲主,所以其指令做法並不複雜,可利用 DCL 控制的權限有:CONNECT
、SELECT
、INSERT
、UPDATE
、DELETE
、EXECUTE
、USAGE
、REFERENCES
。
根據不一樣的 DBMS 以及不一樣的安全性實體,其支持的權限控制也有所不一樣。
(如下爲 DML 語句用法)
增刪改查,又稱爲 CRUD,數據庫基本操做中的基本操做。
INSERT INTO
語句用於向表中插入新記錄。
插入完整的行
INSERT INTO user VALUES (10, 'root', 'root', 'xxxx@163.com');
插入行的一部分
INSERT INTO user(username, password, email) VALUES ('admin', 'admin', 'xxxx@163.com');
插入查詢出來的數據
INSERT INTO user(username) SELECT name FROM account;
UPDATE
語句用於更新表中的記錄。
UPDATE user SET username='robot', password='robot' WHERE username = 'root';
DELETE
語句用於刪除表中的記錄。TRUNCATE TABLE
能夠清空表,也就是刪除全部行。
刪除表中的指定數據
DELETE FROM user WHERE username = 'robot';
清空表中的數據
TRUNCATE TABLE user;
SELECT
語句用於從數據庫中查詢數據。DISTINCT
用於返回惟一不一樣的值。它做用於全部列,也就是說全部列的值都相同纔算相同。LIMIT
限制返回的行數。能夠有兩個參數,第一個參數爲起始行,從 0 開始;第二個參數爲返回的總行數。ASC
:升序(默認)DESC
:降序
查詢單列
SELECT prod_name FROM products;
查詢多列
SELECT prod_id, prod_name, prod_price FROM products;
查詢全部列
ELECT * FROM products;
查詢不一樣的值
SELECT DISTINCT vend_id FROM products;
限制查詢結果
-- 返回前 5 行 SELECT * FROM mytable LIMIT 5; SELECT * FROM mytable LIMIT 0, 5; -- 返回第 3 ~ 5 行 SELECT * FROM mytable LIMIT 2, 3;
子查詢是嵌套在較大查詢中的 SQL 查詢。子查詢也稱爲 內部查詢或 內部選擇,而包含子查詢的語句也稱爲 外部查詢或 外部選擇。
SELECT
,INSERT
,UPDATE
或 DELETE
語句內或另外一個子查詢中。SELECT
語句的 WHERE
子句中添加。>
,<
,或 =
。比較運算符也能夠是多行運算符,如 IN
,ANY
或 ALL
。()
括起來。
子查詢的子查詢
SELECT cust_name, cust_contact FROM customers WHERE cust_id IN (SELECT cust_id FROM orders WHERE order_num IN ( SELECT order_num FROM orderitems WHERE prod_id = 'RGAN01' ) );
WHERE
子句用於過濾記錄,即縮小訪問數據的範圍。WHERE
後跟一個返回 true
或 false
的條件。WHERE
能夠與 SELECT
,UPDATE
和 DELETE
一塊兒使用。WHERE
子句中使用的操做符
SELECT
語句中的 WHERE
子句
SELECT * FROM Customers WHERE cust_name = 'Kids Place';
UPDATE
語句中的 WHERE
子句
UPDATE Customers SET cust_name = 'Jack Jones' WHERE cust_name = 'Kids Place';
DELETE
語句中的 WHERE
子句
DELETE FROM Customers WHERE cust_name = 'Kids Place';
IN
操做符在 WHERE
子句中使用,做用是在指定的幾個特定值中任選一個值。BETWEEN
操做符在 WHERE
子句中使用,做用是選取介於某個範圍內的值。IN 示例
SELECT * FROM products WHERE vend_id IN ('DLL01', 'BRS01');
BETWEEN 示例
SELECT * FROM products WHERE prod_price BETWEEN 3 AND 5;
AND
、OR
、NOT
是用於對過濾條件的邏輯處理指令。AND
優先級高於 OR
,爲了明確處理順序,可使用 ()
。AND
操做符表示左右條件都要知足。OR
操做符表示左右條件知足任意一個便可。NOT
操做符用於否認一個條件。AND 示例
SELECT prod_id, prod_name, prod_price FROM products WHERE vend_id = 'DLL01' AND prod_price <= 4;
OR 示例
SELECT prod_id, prod_name, prod_priceFROM productsWHERE vend_id = 'DLL01' OR vend_id = 'BRS01';
NOT 示例
SELECT * FROM products WHERE prod_price NOT BETWEEN 3 AND 5;
LIKE
操做符在 WHERE
子句中使用,做用是肯定字符串是否匹配模式。LIKE
。LIKE
支持兩個通配符匹配選項:%
和 _
。%
表示任何字符出現任意次數。_
表示任何字符出現一次。% 示例
SELECT prod_id, prod_name, prod_price FROM products WHERE prod_name LIKE '%bean bag%';
_ 示例
SELECT prod_id, prod_name, prod_price FROM products WHERE prod_name LIKE '__ inch teddy bear';
- 若是一個
JOIN
至少有一個公共字段而且它們之間存在關係,則該JOIN
能夠在兩個或多個表上工做。- 鏈接用於鏈接多個表,使用
JOIN
關鍵字,而且條件語句使用ON
而不是WHERE
。JOIN
保持基表(結構和數據)不變。JOIN
有兩種鏈接類型:內鏈接和外鏈接。- 內鏈接又稱等值鏈接,使用 INNER
JOIN
關鍵字。在沒有條件語句的狀況下返回笛卡爾積。- 自鏈接能夠當作內鏈接的一種,只是鏈接的表是自身而已。
- 天然鏈接是把同名列經過 = 測試鏈接起來的,同名列能夠有多個。
- 內鏈接 vs 天然鏈接
- 內鏈接提供鏈接的列,而天然鏈接自動鏈接全部同名列。
- 外鏈接返回一個表中的全部行,而且僅返回來自次表中知足鏈接條件的那些行,即兩個表中的列是相等的。外鏈接分爲左外鏈接、右外鏈接、全外鏈接(Mysql 不支持)。
- 左外鏈接就是保留左表沒有關聯的行。
- 右外鏈接就是保留右表沒有關聯的行。
- 鏈接 vs 子查詢
- 鏈接能夠替換子查詢,而且比子查詢的效率通常會更快。
SELECT vend_name, prod_name, prod_price FROM vendors INNER JOIN products ON vendors.vend_id = products.vend_id;
SELECT c1.cust_id, c1.cust_name, c1.cust_contact FROM customers c1, customers c2 AND c2.cust_contact = 'Jim Jones';
SELECT * FROM Products NATURAL JOIN Customers;
SELECT customers.cust_id, orders.order_num FROM customers LEFT JOIN orders ON customers.cust_id = orders.cust_id;
SELECT customers.cust_id, orders.order_num FROM customers RIGHT JOIN orders ON customers.cust_id = orders.cust_id;
UNION
運算符將兩個或更多查詢的結果組合起來,並生成一個結果集,其中包含來自 UNION
中參與查詢的提取行。UNION
基本規則UNION ALL
。ORDER BY
子句,而且必須位於語句的最後。組合查詢
SELECT cust_name, cust_contact, cust_email FROM customers WHERE cust_state IN ('IL', 'IN', 'MI') UNION SELECT cust_name, cust_contact, cust_email FROM customers WHERE cust_name = 'Fun4All';
JOIN
中鏈接表的列可能不一樣,但在 UNION
中,全部查詢的列數和列順序必須相同。UNION
將查詢以後的行放在一塊兒(垂直放置),但 JOIN
將查詢以後的列放在一塊兒(水平放置),即它構成一個笛卡爾積。🔔 注意:不一樣數據庫的函數每每各不相同,所以不可移植。本節主要以 Mysql 的函數爲例。
其中, SOUNDEX() 能夠將一個字符串轉換爲描述其語音表示的字母數字模式。
SELECT * FROM mytable WHERE SOUNDEX(col1) = SOUNDEX('apple')
YYYY-MM-DD
HH:MM:SS
mysql> SELECT NOW();
2018-4-14 20:25:11
AVG()
會忽略 NULL 行。
使用 DISTINCT 可讓彙總函數值彙總不一樣的值。
SELECT AVG(DISTINCT col1) AS avg_colFROM mytable
ORDER BY
用於對結果集進行排序。ASC
:升序(默認)DESC
:降序指定多個列的排序方向
SELECT * FROM products ORDER BY prod_price DESC, prod_name ASC;
GROUP BY
子句將記錄分組到彙總行中。GROUP BY
爲每一個組返回一個記錄。GROUP BY
一般還涉及聚合:COUNT,MAX,SUM,AVG 等。GROUP BY
能夠按一列或多列進行分組。GROUP BY
按分組字段進行排序後,ORDER BY
能夠以彙總字段來進行排序。分組
SELECT cust_name, COUNT(cust_address) AS addr_num FROM Customers GROUP BY cust_name;
分組後排序
SELECT cust_name, COUNT(cust_address) AS addr_num FROM Customers GROUP BY cust_name ORDER BY cust_name DESC;
HAVING
用於對彙總的 GROUP BY
結果進行過濾。HAVING
要求存在一個 GROUP BY
子句。WHERE
和 HAVING
能夠在相同的查詢中。HAVING
vs WHERE
WHERE
和 HAVING
都是用於過濾。HAVING
適用於彙總的組記錄;而 WHERE 適用於單個記錄。使用 WHERE 和 HAVING 過濾數據
SELECT cust_name, COUNT(*) AS num FROM Customers WHERE cust_email IS NOT NULL GROUP BY cust_name HAVING COUNT(*) >= 1;
(如下爲 DDL 語句用法)
DDL 的主要功能是定義數據庫對象(如:數據庫、數據表、視圖、索引等)。
CREATE DATABASE test;
DROP DATABASE test;
USE test;
普通建立
CREATE TABLE user ( id int(10) unsigned NOT NULL COMMENT 'Id', username varchar(64) NOT NULL DEFAULT 'default' COMMENT '用戶名', password varchar(64) NOT NULL DEFAULT 'default' COMMENT '密碼', email varchar(64) NOT NULL DEFAULT 'default' COMMENT '郵箱') COMMENT='用戶表';
根據已有的表建立新表
CREATE TABLE vip_user AS SELECT * FROM user;
DROP TABLE user;
添加列
ALTER TABLE userADD age int(3);
刪除列
ALTER TABLE userDROP COLUMN age;
修改列
ALTER TABLE `user`MODIFY COLUMN age tinyint;
添加主鍵
ALTER TABLE userADD PRIMARY KEY (id);
刪除主鍵
ALTER TABLE userDROP PRIMARY KEY;
- 定義
- 視圖是基於 SQL 語句的結果集的可視化的表。
- 視圖是虛擬的表,自己不包含數據,也就不能對其進行索引操做。對視圖的操做和對普通表的操做同樣。
- 做用
- 簡化複雜的 SQL 操做,好比複雜的聯結;
- 只使用實際表的一部分數據;
- 經過只給用戶訪問視圖的權限,保證數據的安全性;
- 更改數據格式和表示。
CREATE VIEW top_10_user_view AS SELECT id, username FROM user WHERE id < 10;
DROP VIEW top_10_user_view;
- 做用
- 經過索引能夠更加快速高效地查詢數據。
- 用戶沒法看到索引,它們只能被用來加速查詢。
- 注意
- 更新一個包含索引的表須要比更新一個沒有索引的表花費更多的時間,這是因爲索引自己也須要更新。所以,理想的作法是僅僅在經常被搜索的列(以及表)上面建立索引。
- 惟一索引
- 惟一索引代表此索引的每個索引值只對應惟一的數據記錄。
CREATE INDEX user_indexON user (id);
CREATE UNIQUE INDEX user_indexON user (id);
ALTER TABLE userDROP INDEX user_index;
SQL 約束用於規定表中的數據規則。
NOT NULL
- 指示某列不能存儲 NULL 值。UNIQUE
- 保證某列的每行必須有惟一的值。PRIMARY KEY
- NOT NULL 和 UNIQUE 的結合。確保某列(或兩個列多個列的結合)有惟一標識,有助於更容易更快速地找到表中的一個特定的記錄。FOREIGN KEY
- 保證一個表中的數據匹配另外一個表中的值的參照完整性。CHECK
- 保證列中的值符合指定的條件。DEFAULT
- 規定沒有給列賦值時的默認值。建立表時使用約束條件:
CREATE TABLE Users ( Id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', Username VARCHAR(64) NOT NULL UNIQUE DEFAULT 'default' COMMENT '用戶名', Password VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '密碼', Email VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '郵箱地址', Enabled TINYINT(4) DEFAULT NULL COMMENT '是否有效', PRIMARY KEY (Id)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用戶表';
(如下爲 TCL 語句用法)
- 不能回退 SELECT 語句,回退 SELECT 語句也沒意義;也不能回退 CREATE 和 DROP 語句。
- MySQL 默認是隱式提交,每執行一條語句就把這條語句當成一個事務而後進行提交。當出現
START TRANSACTION
語句時,會關閉隱式提交;當COMMIT
或ROLLBACK
語句執行後,事務會自動關閉,從新恢復隱式提交。- 經過
set autocommit=0
能夠取消自動提交,直到set autocommit=1
纔會提交;autocommit 標記是針對每一個鏈接而不是針對服務器的。- 指令
START TRANSACTION
- 指令用於標記事務的起始點。SAVEPOINT
- 指令用於建立保留點。ROLLBACK TO
- 指令用於回滾到指定的保留點;若是沒有設置保留點,則回退到START TRANSACTION
語句處。COMMIT
- 提交事務。
-- 開始事務START TRANSACTION;-- 插入操做 A START TRANSACTION; -- 插入操做 AINSERT INTO `user` VALUES (1, 'root1', 'root1', 'xxxx@163.com'); -- 建立保留點 updateA SAVEPOINT updateA; -- 插入操做 B INSERT INTO `user` VALUES (2, 'root2', 'root2', 'xxxx@163.com'); -- 回滾到保留點 updateA ROLLBACK TO updateA; -- 提交事務,只有操做 A 生效 COMMIT;
(如下爲 DCL 語句用法)
- GRANT 和 REVOKE 可在幾個層次上控制訪問權限:
- 整個服務器,使用 GRANT ALL 和 REVOKE ALL;
- 整個數據庫,使用 ON database.*;
- 特定的表,使用 ON database.table;
- 特定的列;
- 特定的存儲過程。
- 新建立的帳戶沒有任何權限。
- 帳戶用 username@host 的形式定義,username@% 使用的是默認主機名。
MySQL 的帳戶信息保存在 mysql 這個數據庫中。
USE mysql;SELECT user FROM user;複製代碼
CREATE USER myuser IDENTIFIED BY 'mypassword';
UPDATE user SET user='newuser' WHERE user='myuser'; FLUSH PRIVILEGES;
DROP USER myuser;
SHOW GRANTS FOR myuser;
GRANT SELECT, INSERT ON *.* TO myuser;
REVOKE SELECT, INSERT ON *.* FROM myuser;
SET PASSWORD FOR myuser = 'mypass';
- 存儲過程能夠當作是對一系列 SQL 操做的批處理;
- 使用存儲過程的好處
- 代碼封裝,保證了必定的安全性;
- 代碼複用;
- 因爲是預先編譯,所以具備很高的性能。
- 建立存儲過程
- 命令行中建立存儲過程須要自定義分隔符,由於命令行是以
;
爲結束符,而存儲過程當中也包含了分號,所以會錯誤把這部分分號當成是結束符,形成語法錯誤。- 包含 in、out 和 inout 三種參數。
- 給變量賦值都須要用 select into 語句。
- 每次只能給一個變量賦值,不支持集合的操做。
DROP PROCEDURE IF EXISTS `proc_adder`; DELIMITER ;; CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_adder`(IN a int, IN b int, OUT sum int) BEGIN DECLARE c int; if a is null then set a = 0; end if; if b is null then set b = 0; end if; set sum = a + b; END;; DELIMITER ;
set @b=5; call proc_adder(2,@b,@s); select @s as sum;
- 遊標(cursor)是一個存儲在 DBMS 服務器上的數據庫查詢,它不是一條 SELECT 語句,而是被該語句檢索出來的結果集。
- 在存儲過程當中使用遊標能夠對一個結果集進行移動遍歷。
- 遊標主要用於交互式應用,其中用戶須要對數據集中的任意行進行瀏覽和修改。
- 使用遊標的四個步驟:
- 聲明遊標,這個過程沒有實際檢索出數據;
- 打開遊標;
- 取出數據;
- 關閉遊標;
DELIMITER $ CREATE PROCEDURE getTotal() BEGIN DECLARE total INT; -- 建立接收遊標數據的變量 DECLARE sid INT; DECLARE sname VARCHAR(10); -- 建立總數變量 DECLARE sage INT; -- 建立結束標誌變量 DECLARE done INT DEFAULT false; -- 建立遊標 DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age>30; -- 指定遊標循環結束時的返回值 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true; SET total = 0; OPEN cur; FETCH cur INTO sid, sname, sage; WHILE(NOT done) DO SET total = total + 1; FETCH cur INTO sid, sname, sage; END WHILE; CLOSE cur; SELECT total; END $ DELIMITER ; -- 調用存儲過程 call getTotal();
觸發器是一種與表操做有關的數據庫對象,當觸發器所在表上出現指定事件時,將調用該對象,即表的操做事件觸發表上的觸發器的執行。
可使用觸發器來進行審計跟蹤,把修改記錄到另一張表中。
MySQL 不容許在觸發器中使用 CALL 語句 ,也就是不能調用存儲過程。
BEGIN
和 END
當觸發器的觸發條件知足時,將會執行 BEGIN
和 END
之間的觸發器執行動做。
🔔 注意:在 MySQL 中,分號;
是語句結束的標識符,遇到分號表示該段語句已經結束,MySQL 能夠開始執行了。所以,解釋器遇到觸發器執行動做中的分號後就開始執行,而後會報錯,由於沒有找到和 BEGIN 匹配的 END。這時就會用到
DELIMITER
命令(DELIMITER 是定界符,分隔符的意思)。它是一條命令,不須要語句結束標識,語法爲:DELIMITER new_delemiter
。new_delemiter
能夠設爲 1 個或多個長度的符號,默認的是分號;
,咱們能夠把它修改成其餘符號,如$
-DELIMITER $
。在這以後的語句,以分號結束,解釋器不會有什麼反應,只有遇到了$
,才認爲是語句結束。注意,使用完以後,咱們還應該記得把它給修改回來。
NEW
和 OLD
NEW
和 OLD
關鍵字,用來表示觸發器的所在表中,觸發了觸發器的那一行數據。INSERT
型觸發器中,NEW
用來表示將要(BEFORE
)或已經(AFTER
)插入的新數據;UPDATE
型觸發器中,OLD
用來表示將要或已經被修改的原數據,NEW
用來表示將要或已經修改成的新數據;DELETE
型觸發器中,OLD
用來表示將要或已經被刪除的原數據;NEW.columnName
(columnName 爲相應數據表某一列名)提示:爲了理解觸發器的要點,有必要先了解一下建立觸發器的指令。
CREATE TRIGGER
指令用於建立觸發器。
語法:
CREATE TRIGGER trigger_name trigger_time trigger_event ON table_name FOR EACH ROW BEGIN trigger_statements END;
說明:
BEFORE
或 AFTER
。INSERT
、UPDATE
或 DELETE
。;
來結尾。示例:
DELIMITER $ CREATE TRIGGER `trigger_insert_user` AFTER INSERT ON `user` FOR EACH ROW BEGIN INSERT INTO `user_history`(user_id, operate_type, operate_time) VALUES (NEW.id, 'add a user', now()); END $ DELIMITER ;
SHOW TRIGGERS;
DROP TRIGGER IF EXISTS trigger_insert_user;
若有錯誤或其它問題,歡迎小夥伴留言評論、指正。若有幫助,歡迎點贊+轉發分享。
歡迎你們關注民工哥的公衆號:民工哥技術之路