模式定義了數據如何存儲、存儲什麼樣的數據以及數據如何分解等信息,數據庫和表都有模式。mysql
主鍵的值不容許修改,也不容許複用(不能使用已經刪除的主鍵值賦給新數據行的主鍵)。sql
SQL(Structured Query Language),標準 SQL 由 ANSI 標準委員會管理,從而稱爲 ANSI SQL。各個 DBMS 都有本身的實現,如 PL/SQL、Transact-SQL 等。數據庫
SQL 語句不區分大小寫,可是數據庫表名、列名和值是否區分依賴於具體的 DBMS 以及配置。安全
SQL 支持如下三種註釋:服務器
# 註釋
SELECT *
FROM mytable; -- 註釋
/* 註釋1
註釋2 */
數據庫建立與使用:網絡
CREATE DATABASE test;
USE test;
CREATE TABLE mytable (
id INT NOT NULL AUTO_INCREMENT,
col1 INT NOT NULL DEFAULT 1,
col2 VARCHAR(45) NULL,
col3 DATE NULL,
PRIMARY KEY (`id`));
添加列app
ALTER TABLE mytable
ADD col CHAR(20);
刪除列函數
ALTER TABLE mytable
DROP COLUMN col;
刪除表性能
DROP TABLE mytable;
普通插入測試
INSERT INTO mytable(col1, col2)
VALUES(val1, val2);
插入檢索出來的數據
INSERT INTO mytable1(col1, col2)
SELECT col1, col2
FROM mytable2;
將一個表的內容插入到一個新表
CREATE TABLE newtable AS
SELECT * FROM mytable;
UPDATE mytable
SET col = val
WHERE id = 1;
DELETE FROM mytable
WHERE id = 1;
TRUNCATE TABLE 能夠清空表,也就是刪除全部行。
TRUNCATE TABLE mytable;
使用更新和刪除操做時必定要用 WHERE 子句,否則會把整張表的數據都破壞。能夠先用 SELECT 語句進行測試,防止錯誤刪除。
相同值只會出現一次。它做用於全部列,也就是說全部列的值都相同纔算相同。
SELECT DISTINCT col1, col2
FROM mytable;
限制返回的行數。能夠有兩個參數,第一個參數爲起始行,從 0 開始;第二個參數爲返回的總行數。
返回前 5 行:
SELECT *
FROM mytable
LIMIT 5;
SELECT *
FROM mytable
LIMIT 0, 5;
返回第 3 ~ 5 行:
SELECT *
FROM mytable
LIMIT 2, 3;
能夠按多個列進行排序,而且爲每一個列指定不一樣的排序方式:
SELECT *
FROM mytable
ORDER BY col1 DESC, col2 ASC;
不進行過濾的數據很是大,致使經過網絡傳輸了多餘的數據,從而浪費了網絡帶寬。所以儘可能使用 SQL 語句來過濾沒必要要的數據,而不是傳輸全部的數據到客戶端中而後由客戶端進行過濾。
SELECT *
FROM mytable
WHERE col IS NULL;
下表顯示了 WHERE 子句可用的操做符
操做符 | 說明 |
---|---|
= | 等於 |
< | 小於 |
> | 大於 |
<> != | 不等於 |
<= !> | 小於等於 |
>= !< | 大於等於 |
BETWEEN | 在兩個值之間 |
IS NULL | 爲 NULL 值 |
應該注意到,NULL 與 0、空字符串都不一樣。
AND 和 OR 用於鏈接多個過濾條件。優先處理 AND,當一個過濾表達式涉及到多個 AND 和 OR 時,可使用 () 來決定優先級,使得優先級關係更清晰。
IN 操做符用於匹配一組值,其後也能夠接一個 SELECT 子句,從而匹配子查詢獲得的一組值。
NOT 操做符用於否認一個條件。
通配符也是用在過濾語句中,但它只能用於文本字段。
% 匹配 >=0 個任意字符;
_ 匹配 ==1 個任意字符;
[ ] 能夠匹配集合內的字符,例如 [ab] 將匹配字符 a 或者 b。用脫字符 ^ 能夠對其進行否認,也就是不匹配集合內的字符。
使用 Like 來進行通配符匹配。
SELECT *
FROM mytable
WHERE col LIKE '[^AB]%'; -- 不以 A 和 B 開頭的任意文本
不要濫用通配符,通配符位於開頭處匹配會很是慢。
在數據庫服務器上完成數據的轉換和格式化的工做每每比客戶端上快得多,而且轉換和格式化後的數據量更少的話能夠減小網絡通訊量。
計算字段一般須要使用 AS 來取別名,不然輸出的時候字段名爲計算表達式。
SELECT col1 * col2 AS alias
FROM mytable;
CONCAT() 用於鏈接兩個字段。許多數據庫會使用空格把一個值填充爲列寬,所以鏈接的結果會出現一些沒必要要的空格,使用 TRIM() 能夠去除首尾空格。
SELECT CONCAT(TRIM(col1), '(', TRIM(col2), ')') AS concat_col
FROM mytable;
各個 DBMS 的函數都是不相同的,所以不可移植,如下主要是 MySQL 的函數。
函 數 | 說 明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行數 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
AVG() 會忽略 NULL 行。
使用 DISTINCT 可讓彙總函數值彙總不一樣的值。
SELECT AVG(DISTINCT col1) AS avg_col
FROM mytable;
函數 | 說明 |
---|---|
LEFT() | 左邊的字符 |
RIGHT() | 右邊的字符 |
LOWER() | 轉換爲小寫字符 |
UPPER() | 轉換爲大寫字符 |
LTRIM() | 去除左邊的空格 |
RTRIM() | 去除右邊的空格 |
LENGTH() | 長度 |
SOUNDEX() | 轉換爲語音值 |
其中, SOUNDEX() 能夠將一個字符串轉換爲描述其語音表示的字母數字模式。
SELECT *
FROM mytable
WHERE SOUNDEX(col1) = SOUNDEX('apple')
函 數 | 說 明 |
---|---|
AddDate() | 增長一個日期(天、周等) |
AddTime() | 增長一個時間(時、分等) |
CurDate() | 返回當前日期 |
CurTime() | 返回當前時間 |
Date() | 返回日期時間的日期部分 |
DateDiff() | 計算兩個日期之差 |
Date_Add() | 高度靈活的日期運算函數 |
Date_Format() | 返回一個格式化的日期或時間串 |
Day() | 返回一個日期的天數部分 |
DayOfWeek() | 對於一個日期,返回對應的星期幾 |
Hour() | 返回一個時間的小時部分 |
Minute() | 返回一個時間的分鐘部分 |
Month() | 返回一個日期的月份部分 |
Now() | 返回當前日期和時間 |
Second() | 返回一個時間的秒部分 |
Time() | 返回一個日期時間的時間部分 |
Year() | 返回一個日期的年份部分 |
mysql> SELECT NOW();
2018-4-14 20:25:11
函數 | 說明 |
---|---|
SIN() | 正弦 |
COS() | 餘弦 |
TAN() | 正切 |
ABS() | 絕對值 |
SQRT() | 平方根 |
MOD() | 餘數 |
EXP() | 指數 |
PI() | 圓周率 |
RAND() | 隨機數 |
分組就是把具備相同的數據值的行放在同一組中。
能夠對同一分組數據使用匯總函數進行處理,例如求分組數據的平均值等。
指定的分組字段除了能按該字段進行分組,也會自動按該字段進行排序。
SELECT col, COUNT(*) AS num
FROM mytable
GROUP BY col;
GROUP BY 自動按分組字段進行排序,ORDER BY 也能夠按彙總字段來進行排序。
SELECT col, COUNT(*) AS num
FROM mytable
GROUP BY col
ORDER BY num;
WHERE 過濾行,HAVING 過濾分組,行過濾應當先於分組過濾。
SELECT col, COUNT(*) AS num
FROM mytable
WHERE col > 2
GROUP BY col
HAVING num >= 2;
分組規定:
子查詢中只能返回一個字段的數據。
能夠將子查詢的結果做爲 WHRER 語句的過濾條件:
SELECT *
FROM mytable1
WHERE col1 IN (SELECT col2
FROM mytable2);
下面的語句能夠檢索出客戶的訂單數量,子查詢語句會對第一個查詢檢索出的每一個客戶執行一次:
SELECT cust_name, (SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id)
AS orders_num
FROM Customers
ORDER BY cust_name;
鏈接用於鏈接多個表,使用 JOIN 關鍵字,而且條件語句使用 ON 而不是 WHERE。
鏈接能夠替換子查詢,而且比子查詢的效率通常會更快。
能夠用 AS 給列名、計算字段和表名取別名,給表名取別名是爲了簡化 SQL 語句以及鏈接相同表。
內鏈接又稱等值鏈接,使用 INNER JOIN 關鍵字。
SELECT A.value, B.value
FROM tablea AS A INNER JOIN tableb AS B
ON A.key = B.key;
能夠不明確使用 INNER JOIN,而使用普通查詢並在 WHERE 中將兩個表中要鏈接的列用等值方法鏈接起來。
SELECT A.value, B.value
FROM tablea AS A, tableb AS B
WHERE A.key = B.key;
在沒有條件語句的狀況下返回笛卡爾積。
自鏈接能夠當作內鏈接的一種,只是鏈接的表是自身而已。
一張員工表,包含員工姓名和員工所屬部門,要找出與 Jim 處在同一部門的全部員工姓名。
子查詢版本
SELECT name
FROM employee
WHERE department = (
SELECT department
FROM employee
WHERE name = "Jim");
自鏈接版本
SELECT e1.name
FROM employee AS e1 INNER JOIN employee AS e2
ON e1.department = e2.department
AND e2.name = "Jim";
天然鏈接是把同名列經過等值測試鏈接起來的,同名列能夠有多個。
內鏈接和天然鏈接的區別:內鏈接提供鏈接的列,而天然鏈接自動鏈接全部同名列。
SELECT A.value, B.value
FROM tablea AS A NATURAL JOIN tableb AS B;
外鏈接保留了沒有關聯的那些行。分爲左外鏈接,右外鏈接以及全外鏈接,左外鏈接就是保留左表沒有關聯的行。
檢索全部顧客的訂單信息,包括尚未訂單信息的顧客。
SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
customers 表:
cust_id | cust_name |
---|---|
1 | a |
2 | b |
3 | c |
orders 表:
order_id | cust_id |
---|---|
1 | 1 |
2 | 1 |
3 | 3 |
4 | 3 |
結果:
cust_id | cust_name | order_id |
---|---|---|
1 | a | 1 |
1 | a | 2 |
3 | c | 3 |
3 | c | 4 |
2 | b | Null |
使用 UNION 來組合兩個查詢,若是第一個查詢返回 M 行,第二個查詢返回 N 行,那麼組合查詢的結果通常爲 M+N 行。
每一個查詢必須包含相同的列、表達式和彙集函數。
默認會去除相同行,若是須要保留相同行,使用 UNION ALL。
只能包含一個 ORDER BY 子句,而且必須位於語句的最後。
SELECT col
FROM mytable
WHERE col = 1
UNION
SELECT col
FROM mytable
WHERE col =2;
視圖是虛擬的表,自己不包含數據,也就不能對其進行索引操做。
對視圖的操做和對普通表的操做同樣。
視圖具備以下好處:
CREATE VIEW myview AS
SELECT Concat(col1, col2) AS concat_col, col3*col4 AS compute_col
FROM mytable
WHERE col5 = val;
存儲過程能夠當作是對一系列 SQL 操做的批處理。
使用存儲過程的好處:
命令行中建立存儲過程須要自定義分隔符,由於命令行是以 ; 爲結束符,而存儲過程當中也包含了分號,所以會錯誤把這部分分號當成是結束符,形成語法錯誤。
包含 in、out 和 inout 三種參數。
給變量賦值都須要用 select into 語句。
每次只能給一個變量賦值,不支持集合的操做。
delimiter //
create procedure myprocedure( out ret int )
begin
declare y int;
select sum(col1)
from mytable
into y;
select y*y into ret;
end //
delimiter ;
call myprocedure(@ret);
select @ret;
在存儲過程當中使用遊標能夠對一個結果集進行移動遍歷。
遊標主要用於交互式應用,其中用戶須要對數據集中的任意行進行瀏覽和修改。
使用遊標的四個步驟:
delimiter //
create procedure myprocedure(out ret int)
begin
declare done boolean default 0;
declare mycursor cursor for
select col1 from mytable;
# 定義了一個 continue handler,當 sqlstate '02000' 這個條件出現時,會執行 set done = 1
declare continue handler for sqlstate '02000' set done = 1;
open mycursor;
repeat
fetch mycursor into ret;
select ret;
until done end repeat;
close mycursor;
end //
delimiter ;
觸發器會在某個表執行如下語句時而自動執行:DELETE、INSERT、UPDATE。
觸發器必須指定在語句執行以前仍是以後自動執行,以前執行使用 BEFORE 關鍵字,以後執行使用 AFTER 關鍵字。BEFORE 用於數據驗證和淨化,AFTER 用於審計跟蹤,將修改記錄到另一張表中。
INSERT 觸發器包含一個名爲 NEW 的虛擬表。
CREATE TRIGGER mytrigger AFTER INSERT ON mytable
FOR EACH ROW SELECT NEW.col into @result;
SELECT @result; -- 獲取結果
DELETE 觸發器包含一個名爲 OLD 的虛擬表,而且是隻讀的。
UPDATE 觸發器包含一個名爲 NEW 和一個名爲 OLD 的虛擬表,其中 NEW 是能夠被修改的,而 OLD 是隻讀的。
MySQL 不容許在觸發器中使用 CALL 語句,也就是不能調用存儲過程。
基本術語:
不能回退 SELECT 語句,回退 SELECT 語句也沒意義;也不能回退 CREATE 和 DROP 語句。
MySQL 的事務提交默認是隱式提交,每執行一條語句就把這條語句當成一個事務而後進行提交。當出現 START TRANSACTION 語句時,會關閉隱式提交;當 COMMIT 或 ROLLBACK 語句執行後,事務會自動關閉,從新恢復隱式提交。
經過設置 autocommit 爲 0 能夠取消自動提交;autocommit 標記是針對每一個鏈接而不是針對服務器的。
若是沒有設置保留點,ROLLBACK 會回退到 START TRANSACTION 語句處;若是設置了保留點,而且在 ROLLBACK 中指定該保留點,則會回退到該保留點。
START TRANSACTION
// ...
SAVEPOINT delete1
// ...
ROLLBACK TO delete1
// ...
COMMIT
基本術語:
除了給表指定字符集和校對外,也能夠給列指定:
CREATE TABLE mytable
(col VARCHAR(10) CHARACTER SET latin COLLATE latin1_general_ci )
DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;
能夠在排序、分組時指定校對:
SELECT *
FROM mytable
ORDER BY col COLLATE latin1_general_ci;
MySQL 的帳戶信息保存在 mysql 這個數據庫中。
USE mysql;
SELECT user FROM user;
建立帳戶
新建立的帳戶沒有任何權限。
CREATE USER myuser IDENTIFIED BY 'mypassword';
修改帳戶名
RENAME myuser TO newuser;
刪除帳戶
DROP USER myuser;
查看權限
SHOW GRANTS FOR myuser;
授予權限
帳戶用 username@host 的形式定義,username@% 使用的是默認主機名。
GRANT SELECT, INSERT ON mydatabase.* TO myuser;
刪除權限
GRANT 和 REVOKE 可在幾個層次上控制訪問權限:
REVOKE SELECT, INSERT ON mydatabase.* FROM myuser;
更改密碼
必須使用 Password() 函數
SET PASSWROD FOR myuser = Password('new_password');