SQL語言基礎
資料庫語言是java專案開發必不可少的一部分。就我目前的理解:它這不就是高階Excel嘛?誠然,它的設計理論、流程比較複雜。對於關係型資料庫如何工作的往後再談。
0、複習內容
- SQL語法基礎
- SQL語句進階
1、SQL語法基礎
1.1 基礎
- 主鍵的值不允許修改,也不可複用
- SQL語句不區分大小寫(但是資料庫表名、列名和值是否區分依賴於具體的DBMS以及配置)
- 三種註釋方法:#、--、/*註釋1*/
- 資料庫建立與使用
CREATE DATABASE test;
USE test;
1.2 建立表
CREATE TABLE myFirstTable( id INT NOT NULL AUTO_INCREMENT, #NOT NULL非空,後接限定值 col INT NOT NULL DEFAULT 1, col2 VARCHAR(45) NULL, col3 DATE NULL, PRIMARY KEY(`id`));
1.3 修改表
-- 新增列
ALTER TABLE myFirstTable
ADD col4 CHAR(20)
AFTER col; # 在col後新增col4
-- 刪除列
ALTER TABLE myFirstTable
DROP COLUMN col4;
-- 刪除表
DROP TABLE myFirstTable;
1.4 插入
-- 普通插入 INSERT INTO myFirstTable(col, col2) VALUES(100, 200); -- 插入檢索出來的資料 INSERT INTO myFirstTable(col, col2) SELECT col, col2 FROM myFirstTable; -- 將一個表的內容插入到一個新表 CREATE TABLE newtable AS SELECT * FROM myFirstTable; # 相當於複製表
1.5 更新
-- 更新表
UPDATE myFirstTable
SET col = 400
WHERE id = 2; # 定語從句
1.6 刪除
-- 刪除資料
DELETE FROM myFirstTable
WHERE id = 1;
-- 清空表
TRUNCATE TABLE myFirstTable; # 刪表跑路嘿嘿
1.7 查詢
-- 查詢表 -- 1. distinct:相同值只會出現一次。它作用於所有列,也就是說所有列的值都相同才算相同。 SELECT DISTINCT col, col2 FROM myFirstTable; -- 2.limit:限制返回的行數。可以有兩個引數,第一個引數為起始行,從 0 開始;第二個引數為返回的總行數。 SELECT * FROM myFirstTable LIMIT 5; #返回前5行 SELECT * FROM myFirstTable LIMIT 2, 3; # 返回3~5行
1.8 排序
- ASC : 升序(預設)
- DESC : 降序
-- 排序,可以按多個列進行排序,優先順序按位次
SELECT * FROM myFirstTable
ORDER BY col DESC, col2 ASC;
1.9 過濾
不進行過濾的資料非常大,導致通過網路傳輸了多餘的資料,從而浪費了網路頻寬。因此儘量使用 SQL 語句來過濾不必要的資料,而不是傳輸所有的資料到客戶端中然後由客戶端進行過濾。
-- 過濾資料
SELECT * FROM myFirstTable
WHERE col2 IS NULL; # 找出col2為空的元組
下表顯示了 WHERE 子句可用的操作符
操作符 | 說明 |
---|---|
= | 等於 |
< | 小於 |
> | 大於 |
<> != | 不等於 |
<= !> | 小於等於 |
>= !< | 大於等於 |
BETWEEN | 在兩個值之間 |
IS NULL | 為 NULL 值 |
應該注意到,NULL 與 0、空字串都不同。
AND 和 OR 用於連線多個過濾條件。優先處理 AND,當一個過濾表示式涉及到多個 AND 和 OR 時,可以使用 () 來決定優先順序,使得優先順序關係更清晰。
IN 操作符用於匹配一組值,其後也可以接一個 SELECT 子句,從而匹配子查詢得到的一組值。
NOT 操作符用於否定一個條件。
1.10 萬用字元
萬用字元也是用在過濾語句中,但它只能用於文字欄位。
- % 匹配 >=0 個任意字元;
- _ 匹配 ==1 個任意字元;
- [ ] 可以匹配集合內的字元,例如 [ab] 將匹配字元 a 或者 b。用脫字元 ^ 可以對其進行否定,也就是不匹配集合內的字元。
使用 Like 來進行萬用字元匹配。不要濫用萬用字元,萬用字元位於開頭處匹配會非常慢。
-- 萬用字元的使用
SELECT * FROM myFirstTable
WHERE col LIKE '[^ab]%'; # 找出不以 A 和 B 開頭的任意文字
1.11 計算欄位
在資料庫伺服器上完成資料的轉換和格式化的工作往往比客戶端上快得多,並且轉換和格式化後的資料量更少的話可以減少網路通訊量。
-- 計算欄位
SELECT col * col2 AS alias # 用as重新命名是常見的
FROM myFirstTable;
SELECT CONCAT(TRIM(col),'(',TRIM(col2),')') AS concat_col # 分隔
FROM myFirstTable;
圖:col*col2相乘 圖:concat函式的應用
1.12 函式
1.12.1 各個 DBMS 的函式都是不相同的,因此不可移植,以下主要是 MySQL 的函式。
函 數 | 說 明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行數 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
-- 函式--avg()示例,AVG() 會忽略 NULL 行。
SELECT AVG(DISTINCT col) AS avg_col # 使用 DISTINCT 可以讓彙總函式值彙總不同的值。
FROM myFirstTable;
1.12.2 日期和時間處理
- 日期格式: YYYY-MM-DD
- 時間格式: HH:MM:SS
函 數 | 說 明 |
---|---|
AddDate() | 增加一個日期(天、周等) |
AddTime() | 增加一個時間(時、分等) |
CurDate() | 返回當前日期 |
CurTime() | 返回當前時間 |
Date() | 返回日期時間的日期部分 |
DateDiff() | 計算兩個日期之差 |
Date_Add() | 高度靈活的日期運算函式 |
Date_Format() | 返回一個格式化的日期或時間串 |
Day() | 返回一個日期的天數部分 |
DayOfWeek() | 對於一個日期,返回對應的星期幾 |
Hour() | 返回一個時間的小時部分 |
Minute() | 返回一個時間的分鐘部分 |
Month() | 返回一個日期的月份部分 |
Now() | 返回當前日期和時間 |
Second() | 返回一個時間的秒部分 |
Time() | 返回一個日期時間的時間部分 |
Year() | 返回一個日期的年份部分 |
mysql> SELECT CURDATE();
2022-4-13
1.12.3 數值處理
函式 | 說明 |
---|---|
SIN() | 正弦 |
COS() | 餘弦 |
TAN() | 正切 |
ABS() | 絕對值 |
SQRT() | 平方根 |
MOD() | 餘數 |
EXP() | 指數 |
PI() | 圓周率 |
RAND() | 隨機數 |
階段總結:以上為SQL語言非常基礎的部分,看到這裡我們還是會認為SQL與Excel沒有啥區別。且往下看吧!
1.15 分組
分組就是把具有相同的資料值的行放在同一組中。
-- 分組
-- 指定的分組欄位除了能按該欄位進行分組,也會自動按該欄位進行排序
SELECT col, COUNT(*) AS num
FROM myfirsttable
GROUP BY col;
-- GROUP BY 自動按分組欄位進行排序,ORDER BY 也可以按彙總欄位來進行排序
SELECT col, COUNT(*) AS num
FROM myfirsttable
GROUP BY col
ORDER BY num;
-- WHERE 過濾行,HAVING 過濾分組,行過濾應當先於分組過濾
SELECT col, COUNT(*) AS num
FROM myfirsttable
WHERE col > 100
GROUP BY col
HAVING num >= 1;
1.16 子查詢
子查詢中只能返回一個欄位的資料。
可以將子查詢的結果作為 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;
1.17 連線
連線用於連線多個表,使用 JOIN 關鍵字,並且條件語句使用 ON 而不是 WHERE。
連線可以替換子查詢,並且比子查詢的效率一般會更快。
可以用 AS 給列名、計算欄位和表名取別名,給表名取別名是為了簡化 SQL 語句以及連線相同表。
1.17.1 內連線
內連線又稱等值連線,使用 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;
在沒有條件語句的情況下返回笛卡爾積。
1.17.2 自連線
自連線可以看成內連線的一種,只是連線的表是自身而已。
一張員工表,包含員工姓名和員工所屬部門,要找出與 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";
1.17.3 自然連線
自然連線是把同名列通過等值測試連線起來的,同名列可以有多個。
內連線和自然連線的區別: 內連線提供連線的列,而自然連線自動連線所有同名列。
SELECT A.value, B.value
FROM tablea AS A NATURAL JOIN tableb AS B;
1.17.4 外連線
外連線保留了沒有關聯的那些行。分為左外連線,右外連線以及全外連線,左外連線就是保留左表沒有關聯的行。
檢索所有顧客的訂單資訊,包括還沒有訂單資訊的顧客。
SELECT customers.`cust_id`, customers.`cust_name`,orders.`order_id`
FROM customers LEFT OUTER JOIN orders
ON customers.`cust_id` = orders.`cust_id`;
1.18 組合查詢
使用 UNION 來組合兩個查詢,如果第一個查詢返回 M 行,第二個查詢返回 N 行,那麼組合查詢的結果一般為 M+N 行。
每個查詢必須包含相同的列、表示式和聚集函式。
預設會去除相同行,如果需要保留相同行,使用 UNION ALL。
只能包含一個 ORDER BY 子句,並且必須位於語句的最後。
SELECT col FROM myfirsttable
WHERE col = 1
UNION
SELECT col FROM myfirsttable
WHERE col = 100;
1.19 檢視
檢視是虛擬的表,本身不包含資料,也就不能對其進行索引操作。
對檢視的操作和對普通表的操作一樣。
檢視具有如下好處:
- 簡化複雜的 SQL 操作,比如複雜的連線;
- 只使用實際表的一部分資料;
- 通過只給使用者訪問檢視的許可權,保證資料的安全性;
- 更改資料格式和表示。
CREATE VIEW myview AS
SELECT Concat(col1, col2) AS concat_col, col3*col4 AS compute_col
FROM mytable
WHERE col5 = val;
1.20 儲存過程
儲存過程可以看成是對一系列 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;
1.21 遊標
在儲存過程中使用遊標可以對一個結果集進行移動遍歷。
遊標主要用於互動式應用,其中使用者需要對資料集中的任意行進行瀏覽和修改。
使用遊標的四個步驟:
- 宣告遊標,這個過程沒有實際檢索出資料;
- 開啟遊標;
- 取出資料;
- 關閉遊標;
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 ;
1.22 觸發器
觸發器會在某個表執行以下語句時而自動執行: 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 語句,也就是不能呼叫儲存過程。
1.23 事務管理
基本術語:
- 事務(transaction)指一組 SQL 語句;
- 回退(rollback)指撤銷指定 SQL 語句的過程;
- 提交(commit)指將未儲存的 SQL 語句結果寫入資料庫表;
- 保留點(savepoint)指事務處理中設定的臨時佔位符(placeholder),你可以對它釋出回退(與回退整個事務處理不同)。
不能回退 SELECT 語句,回退 SELECT 語句也沒意義;也不能回退 CREATE 和 DROP 語句。
MySQL 的事務提交預設是隱式提交,每執行一條語句就把這條語句當成一個事務然後進行提交。當出現 START TRANSACTION 語句時,會關閉隱式提交;當 COMMIT 或 ROLLBACK 語句執行後,事務會自動關閉,重新恢復隱式提交。
通過設定 autocommit 為 0 可以取消自動提交;autocommit 標記是針對每個連線而不是針對伺服器的。
如果沒有設定保留點,ROLLBACK 會回退到 START TRANSACTION 語句處;如果設定了保留點,並且在 ROLLBACK 中指定該保留點,則會回退到該保留點。
START TRANSACTION
// ...
SAVEPOINT delete1
// ...
ROLLBACK TO delete1
// ...
COMMIT
1.24 字符集
基本術語:
- 字符集為字母和符號的集合;
- 編碼為某個字符集成員的內部表示;
- 校對字元指定如何比較,主要用於排序和分組。
除了給表指定字符集和校對外,也可以給列指定:
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;
1.25 許可權管理
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 可在幾個層次上控制訪問許可權:
- 整個伺服器,使用 GRANT ALL 和 REVOKE ALL;
- 整個資料庫,使用 ON database.*;
- 特定的表,使用 ON database.table;
- 特定的列;
- 特定的儲存過程。
REVOKE SELECT, INSERT ON mydatabase.* FROM myuser;
更改密碼
必須使用 Password() 函式
SET PASSWROD FOR myuser = Password('new_password');
階段總結:SQL語法基礎大概就是這些,下半部分明顯區別於Excel,或者Excel附屬於SQL?
整理自@pdai,本文僅做了部分視覺化作業和整理。
著作權歸https://pdai.tech所有。 連結:https://www.pdai.tech/md/db/sql-lan/sql-lan.html