30.3. MySQL四種語句操作,SQL語法等簡介
20世紀70年代,IBM開發出SQL,用於DB2
1981年,IBM推出SQL/DS數據庫
業內標準微軟和Sybase的T-SQL,Oracle的PL/SQL
SQL作為關系型數據庫所使用的標準語言,最初是基於IBM的實現在1986年被批準的。 1987年,“國際標準化組織(ISO)” 把ANSI(美國國家標準化組織)SQL作為國際標準。
SQL:ANSI SQL
SQL-1986, SQL-1989, SQL-1992, SQL-1999, SQL-2003,SQL-2008, SQL-2011
SQL語言規範
- 在數據庫系統中,SQL語句不區分大小寫(建議用大寫)
- SQL語句可單行或多行書寫,以“;” 結尾
- 關鍵詞不能跨多行或簡寫
- 用空格和縮進來提高語句的可讀性
- 子句通常位於獨立行,便於編輯,提高可讀性
- 註釋:
- SQL標準:
/*註釋內容*/ : 多行註釋
-- 註釋內容 : 單行註釋,註意有空格 - MySQL註釋:
#
- SQL標準:
數據庫對象
- 數據庫的組件(對象):
數據庫、表、索引、視圖、用戶、存儲過程、函數、觸發器、事件調度器等 - 命名規則:
必須以字母開頭
可包括數字和三個特殊字符(# _ $)
不要使用MySQL的保留字
同一database(Schema)下的對象不能同名
SQL語句分類:
- DDL: Data Defination Language 數據定義語言 :命令後面跟database,table
CREATE,DROP,ALTER - DML: Data Manipulation Language 數據操縱語言 : 命令後面跟record
INSERT,DELETE,UPDATE - DCL:Data Control Language 數據控制語言
GRANT,REVOKE,COMMIT,ROLLBACK - DQL:Data Query Language 數據查詢語言
SELECT
SQL語句構成
- SQL語句構成:
Keyword組成clause
多條clause組成語句 - 示例:
SELECT * :SELECT子句
FROM products : FROM子句
WHERE price>400 :WHERE子句 - 說明:一組SQL語句,由三個子句構成,SELECT,FROM和WHERE是關鍵字
註意點1:
- SQL語句的對象是大小寫敏感的,必須針對寫的一字不錯(比如數據庫名字,表的名字),但是其他的語句大小寫不敏感,怎麽寫都可以(註意表中的字段名字大小寫不敏感,可以隨意寫,不過一般還是寫的和字段一樣比較好)
- SQL語言的多行註釋可以寫在一個命令的中間,不過一般也不這樣寫,都是些在命令的前面或者後面。MySQL可用#註釋一行,這是自己獨有的註釋方式。
數據庫操作
- 創建數據庫:
CREATE DATABASE|SCHEMA [IF NOT EXISTS] ‘DB_NAME‘;
CHARACTER SET ‘character set name’COLLATE ‘collate name‘ - 修改數據庫:
ALTER DATABASE DB_NAME character set utf8; - 刪除數據庫
DROP DATABASE|SCHEMA [IF EXISTS] ‘DB_NAME‘; - 查看支持所有字符集:
SHOW CHARACTER SET; - 查看支持所有排序規則:
SHOW COLLATION; - 獲取命令使用幫助:
mysql> HELP KEYWORD; - 查看數據庫列表:
mysql> SHOW DATABASES;
表
表:二維關系
- 設計表:遵循規範
- 定義:字段,索引
字段:字段名,字段數據類型,修飾符
約束,索引:應該創建在經常用作查詢條件的字段上
創建表
創建表:CREATE TABLE
(1) 直接創建
(2) 通過查詢現存表創建;新表會被直接插入查詢而來的數據
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)] [table_options] [partition_options] select_statement
(3) 通過復制現存的表的表結構創建,但不復制數據
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) }
- 註意:
Storage Engine是指表類型,也即在表創建時指明其使用的存儲引擎,同一庫中不同表可以使用不同的存儲引擎 - 同一個庫中表建議要使用同一種存儲引擎類型
表操作1
- 查看所有的引擎:SHOW ENGINES
- 查看表:SHOW TABLES [FROM db_name]
- 查看表結構:DESC [db_name.]tb_name
SHOW COLUMNS FROM [db_name.]tb_name - 刪除表:DROP TABLE [IF EXISTS] tb_name
- 查看表創建命令:SHOW CREATE TABLE tbl_name
- 查看表狀態:SHOW TABLE STATUS LIKE ‘tbl_name’
- 查看庫中所有表狀態:SHOW TABLE STATUS FROM db_name
- 註意:加上\G在命令的後面,可以每一行豎著顯示
數據類型
數據類型:
- 數據長什麽樣
- 數據需要多少空間來存放
系統內置數據類型和用戶定義數據類型
MySql支持多種列類型: - 數值類型
- 日期/時間類型
- 字符串(字符)類型
選擇正確的數據類型對於獲得高性能至關重要,三大原則: - 更小的通常更好,盡量使用可正確存儲數據的最小數據類型
- 簡單就好,簡單數據類型的操作通常需要更少的CPU周期
- 盡量避免NULL,包含為NULL的列,對MySQL更難優化
數據類型分類
更詳細可見官方文檔:
https://dev.mysql.com/doc/refman/8.0/en/data-types.html
- 整型
- tinyint(m) 1個字節 範圍(-128~127)
- smallint(m) 2個字節 範圍(-32768~32767)
- mediumint(m) 3個字節 範圍(-8388608~8388607)
- int(m) 4個字節 範圍(-2147483648~2147483647)
- bigint(m) 8個字節 範圍(+-9.22*10的18次方)
註1:加了unsigned,則最大值翻倍,如:tinyint unsigned的取值範圍為(0~255)
註2:int(m)裏的m是表示SELECT查詢結果集中的顯示寬度,並不影響實際的取值範圍,規定了MySQL的一些交互工具(例如MySQL命令行客戶端)用來顯示字符的個數。對於存儲和計算來說,Int(1)和Int(20)是相同的 - BOOL,BOOLEAN:布爾型,是TINYINT(1)的同義詞。zero值被視為假,非zero值視為真
- 浮點型(float和double),近似值
float(m,d) 單精度浮點型 8位精度(4字節) m總個數,d小數位
double(m,d) 雙精度浮點型16位精度(8字節) m總個數,d小數位
例:設一個字段定義為float(6,3),如果插入一個數123.45678,實際數據庫裏存的是123.457,但總個數還以實際為準,即6位 - 定點數
在數據庫中存放的是精確值,存為十進制
decimal(m,d) 參數 m < 65 是總個數,d < 30且 d < m 是小數位
MySQL5.0和更高版本將數字打包保存到一個二進制字符串中(每4個字節存9個數字)。例如,decimal(18,9)小數點兩邊將各存儲9個數字,一共使用9個字節:小數點前的數字用4個字節,小數點後的數字用4個字節,小數點本身占1個字節
浮點類型在存儲同樣範圍的值時,通常比decimal使用更少的空間。 float使用4個字節存儲。double占用8個字節因為需要額外的空間和計算開銷,所以應該盡量只在對小數進行精確計算時才使用decimal——例如存儲財務數據。但在數據量比較大的時候,可以考慮使用bigint代替decimal - 字符串(char,varchar,_text)
char(n) 固定長度,最多255個字符 :查詢速度塊
varchar(n) 可變長度,最多65535個字符 :查詢速度慢
tinytext 可變長度,最多255個字符
text 可變長度,最多65535個字符
mediumtext 可變長度,最多2的24次方-1個字符
longtext 可變長度,最多2的32次方-1個字符
BINARY(M) 固定長度,可存二進制或字符,長度為0-M字節
VARBINARY(M) 可變長度,可存二進制或字符,允許長度為0-M字節
內建類型:ENUM枚舉, SET集合 - 二進制數據:BLOB
BLOB和text存儲方式不同,TEXT以文本方式存儲,英文存儲區分大小寫,而Blob是以二進制方式存儲,不分大小寫
BLOB存儲的數據只能整體讀出
TEXT可以指定字符集,BLOB不用指定字符集 - 日期時間類型
date 日期 ‘2008-12-2‘
time 時間 ‘12:25:36‘
datetime 日期時間 ‘2008-12-2 22:06:44‘
timestamp 自動存儲記錄修改時間
YEAR(2), YEAR(4):年份
註意:timestamp字段裏的時間數據會隨其他字段修改的時候自動刷新,這個數據類型的字段可以存放這條記錄最後被修改的時間
修飾符
所有類型:
? NULL 數據列可包含NULL值
? NOT NULL 數據列不允許包含NULL值
? DEFAULT 默認值
? PRIMARY KEY 主鍵
? UNIQUE KEY 唯一鍵
? CHARACTER SET name 指定一個字符集
數值型
? AUTO_INCREMENT 自動遞增,適用於整數類型
? UNSIGNED 無符號
創建(定義)表示例
- CREATE TABLE students (id int UNSIGNED NOT NULL PRIMARYKEY,name VARCHAR(20)NOT NULL,age tinyint UNSIGNED);
- DESC students;
- CREATE TABLE students2 (id int UNSIGNED NOT NULL ,name VARCHAR(20) NOT NULL,age tinyint UNSIGNED,gender ENUM(‘m‘,‘f‘) DEFAULT ‘m‘ ,PRIMARY KEY(id,name));
- 註意,只要是char類型的,不論是字段中還是表中的相對應的char類型中的數據,都需要加上單引號引起來,不然會報錯
- 上面3中定義的primary key是復合主鍵,查看help create table中可以看到。
表操作2
DROP TABLE [IF EXISTS] ‘tbl_name‘;
ALTER TABLE ‘tbl_name‘
字段:
添加字段:add
ADD col1 data_type [FIRST|AFTER col_name]
刪除字段:drop
修改字段:
alter(默認值), change(字段名), modify(字段屬性)
索引:
添加索引:add index
刪除索引:drop index
表選項
修改:
查看表上的索引:SHOW INDEXES FROM [db_name.]tbl_name;
查看幫助:Help ALTER TABLE
修改表示例:
ALTER TABLE students RENAME s1;
ALTER TABLE s1 ADD phone varchar(11) AFTER name;
ALTER TABLE s1 MODIFY phone int;
ALTER TABLE s1 CHANGE COLUMN phone mobile char(11);
ALTER TABLE s1 DROP COLUMN mobile;
ALTER TABLE s1 character set utf8;
ALTER TABLE s1 change name name varchar(20) character set utf8;
Help ALTER TABLE 查看幫助
ALTER TABLE students ADD gender ENUM(‘m‘,‘f‘)
ALETR TABLE students CHANGE id sid int UNSIGNED NOT NULL PRIMARY KEY;
ALTER TABLE students drop primary key ;
ALTER TABLE students ADD UNIQUE KEY(name);
ALTER TABLE students ADD INDEX(age);
ALTER TABLE students drop primary key ;
DESC students;
SHOW INDEXES FROM students;
ALTER TABLE students DROP age;
註意點2(DDL語句):
- 可以進入數據庫以後用help create [database | table ...] 來查看幫助如何創建數據庫和表等等
- 創建數據庫database的時候可以選擇要創建的字符集以及它的排序規則是什麽(創建的時候就可以定義寫上),創建之後則用alter命令修改,
- 可以用show character set命令來查看當前數據庫支持的字符集以及其對應的默認的排序規則都有哪些。(utf8,utf8mb4,latin1等等)
- show collation查看排序規則
- 用show create database DATABASE_NAME 來查看創建的數據庫的默認字符集是什麽
- help show,help alter命令來查看幫助
- 除了2中提到的查看數據庫字符集的方式,還可以直接進入database對應的文件夾內(註意要進入到數據庫對應的文件夾下的子文件夾database目錄內),其中的*.opt文件中就記錄著當前對應database的字符集和排序方式。
- 不過這樣的方式每次創建一個新的數據庫都無法指定自己想要的字符集和排序方式,可以直接把它寫入到配置文件中,指定整個mysql服務的字符集和排序方式(進入數據庫之後可以用status查看),具體的配置選項參考下面的變量或者官網的選項說明。
- 註意下劃線和橫線在配置選項中沒有區別(寫在my.cnf中的)
下面是源碼編譯時用Cmake選項修改過的mysql數據庫服務為utf8mb4字符集的這些參數:
14:29[[email protected] ~]# mysqladmin variable -p123456 | grep character
| character_set_client | utf8mb4
| character_set_connection | utf8mb4
| character_set_database | utf8mb4
| character_set_filesystem | binary
| character_set_results | utf8mb4
| character_set_server | utf8mb4
| character_set_system | utf8
| character_sets_dir | /app/mysql/share/charsets/
14:29[[email protected] ~]# mysqladmin variable -p123456 | grep collation
| collation_connection | utf8mb4_general_ci
| collation_database | utf8mb4_general_ci
| collation_server | utf8mb4_general_ci
下面是二進制安裝未修改的默認的mysql字符集:
14:28[[email protected] ~]# mysqladmin -S/data/mysql/3307/socket/mysql.sock variable | grep character
| character_set_client | latin1
| character_set_connection | latin1
| character_set_database | latin1
| character_set_filesystem | binary
| character_set_results | latin1
| character_set_server | latin1
| character_set_system | utf8
| character_sets_dir | /usr/local/mariadb-10.2.23-linux-x86_64/share/charsets/
14:36[[email protected] ~]# mysqladmin -S/data/mysql/3307/socket/mysql.sock variable | grep collation
| collation_connection | latin1_swedish_ci
| collation_database | latin1_swedish_ci
| collation_server | latin1_swedish_ci
可在/etc/mysql/my.cnf中的[mysqld]下添加一行(只需要改這一項即可修改全部的,不過要重啟):
[mysqld]:
character-set-server
1. 註意在,多實例的情況下,如果啟動腳本中,mysqld330X的safe的參數選項選擇配置文件時添加了extra的話,這個位置的my.cnf是能夠控制所有實例的,如果沒有加extra,這只能進入到每一個示例中去修改了。(類似於mysql連接時的命令的extra)
2. 建議的方式是/data/mysql/my.cnf中只寫相同的項目,而/data/mysql/330X/etc/my.cnf寫不同的項目
3. 不過需要註意優先級是按照覆蓋的方式來寫的,要註意/etc/my.cnf 這些其它的配置文件中不要寫上不想要的配置,不然如果/data/mysql/330X/etc/my.cnf中如果沒有寫這些在前面的配置文件中寫入過的選項的話,就會以前面的參數為準了。可能會造成自己一些不想修改的選項被修改了。
4. 經測試果然按照所想的,在這裏優先級最高的(也就是最後使用的配置文件會把前面的配置給覆蓋掉)文件就是這個safe腳本參數extra後面指定的文件(註意之前不加extra的時候只用了這個配置文件,現在是額外用了這個配置文件,不過它是最後一個使用的,覆蓋掉前面的設置,因此優先級最高)。因此,就算前面的配置文件寫了家目錄,端口號等等,只要在最後的這個配置文件中也寫入並修改為自己想要的設置的話,前面配置中寫入的都會被覆蓋不使用。因此也不會影響使用~
5. 在這裏就可以利用這種方式只寫一次修改全部實例的字符集了,寫在前面的總的配置文件中,extra中不寫這一項即可。
6. 註意用mysql連接的時候也可以加上參數mysql -S/data/mysql/3307/socket/mysql.sock --default-character-set=utf8mb4 ,讓連接的客戶端的字符集和服務器端的字符集完全一致
- drop database DATABASE_NAME 其實就是刪除對應的database的目錄,(同理drop table也就是刪除其對應的表的定義和數據文件)
- 不過註意不要用rm的方式刪除,要用命令的方式刪除才可
- help create table可看到創建表的三種方式以及各種類型等,這裏就不解釋了
- 註意,只要是char類型的,不論是字段中還是表中的相對應的char類型中的數據,都需要加上單引號引起來,不然會報錯;同時如果創建表的命令太長的話可以直接回車換行再繼續書寫即可。
- 創建之後可以用desc TABLE_NAME 查看表的定義
- 用show create table TABLE_NAME 查看表的字符集等相關信息(這個字符集創建的時候也可以寫上,具體查看6中的幫助所寫哪些data類型需要字符集)
- 創建完表之後,在相對應的磁盤上的數據庫目錄下的database的目錄中就會增加一個表的名字相對應的.frm文件,這個文件就是表的定義的文件。
- 註意老版本的數據庫的數據都存放在數據庫目錄下的(不是database目錄下)的ibdata1文件中,不管是哪個database下的哪個表都往這裏存放,非常不好。而新版本已經分別放到對應的database目錄中的文件中了。
- 新版本的表對應存放的數據就在對應的database目錄中的另外一個文件,就是.idb後綴文件中。
- show table status like 後面的表的名字,必須加上單引號引起來。可以用匹配的方式(利用%和_符號)。命令後面可以加上\G用於把每行豎行顯示。
- ++創建表的第二種方式++是比第一種方式多了一個參考select的命令的結果(select 命令選擇的字段的定義會被復制過來,原先字段內數據同樣會被一並復制過來,註意和第三種克隆方式的區別:克隆方式只克隆表的定義,不克隆數據;它把字段的定義作為參考,加入新創建的表的字段定義中,註意其中有些信息會丟失,比如原先字段的主鍵信息等);
- 附加:在數據庫外面想要select數據庫內的表或者字段,可以用DATABASE.TABLE中間的加點的方式來引用。
- ++創建表的第三種方式++直接就是克隆原先的表的定義過來,並且與第二種方式相比,會保留字段的主鍵信息等,相當於和被克隆的表的定義一模一樣;
- 但是需要註意,克隆的方式也會把被克隆的表的字符集的定義和順序一並克隆過來,不論當前的database的字符集是什麽,它只看原來的表的字符集,這一點尤其要註意。可以用show create table TABLE_NAME來查看。
- 另外有一點就是,表的默認字符集和字段(char類型的字段)的字符集可以是不相同的,在create table的幫助中也可以看到char類型的字段定義的時候是可以定義字符集的,因此用克隆的方式就算用下面的方式把表的默認字符集改變了,但是克隆過來的字段字符集沒有變化,仍舊是原先數據庫默認字符集(latin1),此時輸入的字符(中文等)因為是在字段的record中,所以還是會亂碼報錯。
- 還有就是上面提到的第二種方式會把select選中的字段中數據一並復制過來,但是會丟失一些字段的額外屬性;第三種方式克隆只會克隆表的定義,數據不復制,但是能保留字段的所有屬性
- 可以創建完表字後用alter table TABLE_NAME character set utf8mb4命令修改表的字符集(註意和字段的字符集的區別)
- 表的修改很少去做,盡量在表創建的時候想好要創建什麽字段。而且表之間的關聯最多不能超過3表。
DML語句
DML: INSERT, DELETE, UPDATE
INSERT:
一次插入一行或多行數據
INSERT語法1
INSERT [L OW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] {VALUES | VALUE} ({expr | DEFAULT},...),(...),... [ ON DUPLICATE KEY UPDATE 如果重復更新之 col_name=expr [, col_name=expr] ... ]
簡化寫法:
INSERT tbl_name [(col1,...)] VALUES (val1,...), (val21,...)
INSERT語法2
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name SET col_name={expr | DEFAULT}, ... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
INSERT語法3
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] SELECT ... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
UPDATE:
UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ... [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]
- 註意:一定要有限制條件,否則將修改所有行的指定字段
限制條件:
WHERE
LIMIT - Mysql 選項:-U|--safe-updates| --i-am-a-dummy
DELETE:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]
可先排序再指定刪除的行數
- 註意:一定要有限制條件,否則將清空表中的所有數據
限制條件:
WHERE
LIMIT - TRUNCATE TABLE tbl_name; 清空表
註意點3(DML語句):
- insert命令後面的value的值一定要和前面的col寫入的順序一一對應,其中一次性可以添加多個record,只需要每一個value後面的值用小括號括起來,之間用逗號分隔開即可。
- 註意如果col的值沒有寫的話,代表後面要添加的value的值要包含所有的字段,同時要按照對應的表中字段的默認排序來寫(可用desc TABLE_NAME查看表中的字段和默認排序從上到下。)
- 當前面的cols選定了要添加的記錄record中的字段時,剩下的沒有被選中的字段必須默認不能為空值或者有其他的屬性(比如說數值型的自動增長,或者有默認的值),不然添加字段的時候如果不可以為空值的字段即沒有特殊的其他屬性又不在添加記錄的時候給它賦值,這個字段就會出現問題。
- 表中的字段盡量不要讓它為空值,要麽默認不為空輸入的時候寫上,要麽默認給它一個值,之後再修改。總之盡量不要為空值。(註意定義字段的時候如果不寫上NOT NULL 或者 DEFAULT的話,這個字段默認可以為空值)
- 添加字段的時候註意字符串和創建字段的時候的枚舉類型一樣,只要是字符類型的數據都要單引號引起來,特殊的:如果選定了cols但是insert命令中有些記錄record的某些字段並不賦值,可以用null來把它設置為空值。註意這裏null不需要加單引號。不過前提是這些字段可以為空值。
- 數據庫的data目錄下有一個隱藏的history日誌文件,它保留了數據庫內進行的操作的歷史命令。當退出數據庫後就會進行更新。
- insert student select * form db2.student2 ;(第三種語法,第二種語法只能添加一行的字段)
- 特別註意:表的記錄操作update和delete命令,修改刪除record的時候一定要加上限制條件,不然會把所有的row都給修改掉。
- 可以在連接數據庫的時候加上-U選項,避免這種不加限制條件的語法進行批量修改的情況發生(會把這種語句當做錯誤語句)
- 或者用別名的方式把mysql永遠加上-U選項
- 或者說在配置文件中的[mysql]欄中(可以寫在/data/mysql/my.cnf中或者說/etc/my.cnf.d/目錄下的客戶端配置文件中等等。)添加一項:safe-updates [=1 | =ture | on |...]
- delete from TABLE_NAME [where_condition],如果不加條件就會把整個表給刪除掉。
- 註意條件的判斷語句參看下面的select中的命令,或者說查看官方解釋文檔http://dev.mysql.com/doc/refman/5.5/en/expressions.html
- 當刪除掉一行,再次添加新的行的時候,如果不指明行中含有的自動增長的數值型字段的值,則它會按照當前表中此字段最後的值來進行增長並添加。而被刪除掉而這一行就會跳過並空著。不過可以添加的時候指明這個空著的值並添加一個記錄進去。
- delete form TABLE_NAME 命令刪除表的速度不如 truncate table TABLE_NAME,因為前者仍舊會記錄到日誌中,後者雖然快但是有一定的危險性,無法回復,所有慎用;不過它倆都是只刪除表中數據,並未刪除表的定義。
- 註意update命令修改表中record的命令只能用set 字段=VALUE的方式,後面加上判斷條件where等。類似insert的第二中方式。
DQL語句
單表查詢
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[SQL_CACHE | SQL_NO_CACHE]
select_expr [, select_expr ...]
[FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[FOR UPDATE | LOCK IN SHARE MODE]
SELECT
- 字段顯示可以使用別名:
col1 AS alias1, col2 AS alias2, ... - WHERE子句:指明過濾條件以實現“選擇”的功能:
過濾條件:布爾型表達式
算術操作符:+, -, *, /, %
比較操作符:=,<=>(相等或都為空), <>, !=(非標準SQL), >, >=, <, <=
BETWEEN min_num AND max_num
IN (element1, element2, ...)
IS NULL
IS NOT NULL- 註意:下面的4 5 6 7用在 where 的++字段++ 後面,當做判斷符號
- DISTINCT 去除重復列
SELECT DISTINCT gender FROM students; - LIKE:
% 任意長度的任意字符
_ 任意單個字符 - RLIKE:正則表達式,索引失效,不建議使用
- REGEXP:匹配字符串可用正則表達式書寫模式,同上
- 邏輯操作符:
NOT
AND
OR
XOR - GROUP BY:根據指定的條件把查詢結果進行“分組”以用於做“聚合”運算
avg(), max(), min(), count(), sum()
HAVING: 對分組聚合運算後的結果指定過濾條件 - ORDER BY: 根據指定的字段對查詢結果進行排序
升序:ASC
降序:DESC - LIMIT [[offset,]row_count]:對查詢的結果進行輸出行數數量限制
- 對查詢結果中的數據請求施加“鎖”
FOR UPDATE: 寫鎖,獨占或排它鎖,只有一個讀和寫
LOCK IN SHARE MODE: 讀鎖,共享鎖,同時多個讀
select示例:
DESC students;
INSERT [INTO] students VALUES(1,‘tom‘,‘m‘),(2,‘alice‘,‘f‘);
INSERT [INTO] students(id,name) VALUES(3,‘jack‘),(4,‘allen‘);
SELECT * FROM students WHERE id < 3;
SELECT * FROM students WHERE gender=‘m‘;
SELECT * FROM students WHERE gender IS NULL;
SELECT * FROM students WHERE gender IS NOT NULL;
SELECT * FROM students ORDER BY name DESC LIMIT 2;
SELECT * FROM students ORDER BY name DESC LIMIT 1,2;
SELECT * FROM students WHERE id >=2 and id <=4
SELECT * FROM students WHERE BETWEEN 2 AND 4
SELECT * FROM students WHERE name LIKE ‘t%’
SELECT * FROM students WHERE name RLIKE ‘.*[lo].*‘;
SELECT id stuid,name as stuname FROM students
註意點4(DQL單表和基礎):
- select命令選擇字段的時候,可以直接在選擇的字段後面加上別名,中間的AS符號可以省略(可以中文,如果用的utf8字符集的話,這裏不用as可以直接加別名的原因就是字段都是以逗號,分隔開的);同樣的,from關鍵字後面的表名也可以加別名。
- 不過需要註意,字段加別名可在select命令結束並顯示結果的時候在字段欄中顯示別名;同時字段和表加了別名之後,在後面的命令中,就可以用別名的方式再次使用這個表或者字段了
- 註意表名加了別名之後,在引用這個表中的字段(select後面,或者條件判斷中on,where having等)都要用這個表的別名方式來引用了。
- select整個語句也可以作為一個整體加別名,把這個select的結果(可看作是一個表,類似view)用這個別名來引用,嵌套等
- select語句的from關鍵字後面也可以限定範圍(where,limit等等)。
- 註意where等判定的時候有多種方式,最常見的就是後面跟的是"(數值型)字段 判斷符號(=>等) VALUE "
- 當然字符型字段也可以判斷:"(字符型)字段 判斷符號(!=,<=>等等) ‘string‘ " ,此時大於小於就是按照字符集排序方式的前後順序來判斷字符串的大小的(可用order by 查看順序)。同時一定要註意string外面要加上單引號引起來。
- where後面的字段後面的判斷符號還可以用like來進行模糊匹配(或者精確匹配)
- 經過測試,在這數據庫裏的字符型的數據不管在哪都要加上引號,數值型的沒有要求。這個要求和命令無關,只要是在數據庫內操作輸入等都要按照這個規則而已。
- where 字段 is [not] null
- SQL註入:註意where後面的語句中可以寫上一個永遠正確的語句比如 1=1(2=2等等) 然後用它與其他的條件進行 OR的關系,就可以達到繞過這個OR所跟的條件判斷的目的,從而來實現一些操作,比如繞過密碼輸入可以寫語句: where password=‘‘ or 1=1 ;
- select 還支持數運算,where後面的語句也可以用類似for的in方式(就相當於=符號,不過不用寫那麽多的OR了),比如where 字段 in (value1,value2,...)
- 正則表達式rlike也可用,但正則則表達式方式無法使用索引,基本上不用。
- 排序分組限定(GROUP BY,ORDER BY,limit)也是在form關鍵字後面,它和where是同一類別的(同級)。
- 註意GROUP BY後面跟的也是字段,它會把整個表中這個字段中相同的record值的行給合並,然後按照前面select選擇的項目(一般就是聚合函數,如果選擇字段的話沒有意義了)進行顯示,把group by後面的字段放到顯示結果的第一列colume上。
- 用group by 的時候,select 後面的字段一定要包含有與group by 後面的字段1相同的字段(不然看不出來結果,雖然不寫也可以),同時select 後面的字段一定要有2聚合函數(這個結果也可以作為別名,前面已經說過),不然也沒有意義了。
- group by 先分組之後,如果還要再次進行條件限定,此時用的關鍵字是having,(類似於where,只不過where是放在group by 前面的關鍵字,having 是放在後面的關鍵字),判斷的符號等基本和where一致。它倆都可以進行條件限定,視情況選擇使用(也可以同時使用,先where,然後group by 最後 having)
附加知識點:count()函數,對字段進行統計的時候count(字段名),其中記錄如果可以為空,則裏面的null值會不作為統計結果,這一點需要註意。對於主鍵字段利用count(主鍵字段)和count(*)的結果則是一致的,都是統計這個表(如果有限定條件的話就是限定條件的)所擁有的所有記錄,因此簡單點可以用count(*)來統計記錄總數。 - group by 後面可以跟多個字段進行多次分組,中間直接用逗號隔開即可。此時就是按照所寫字段的從左往右的順序一個一個分組。
- order by 排序也可以與前面說的where,group by ,having 同時使用;同時它也像group by一樣可以對多列按照從左往右的順序進行排序(因為排序並不會像group by一樣把字段中重復的值的行給換成一個,註意多列排序的時候最好不要與group by 同時使用)。
- limit命令用在select最後,可以取出需要的行,limit OFFSET,ROW ; 其中offset 和 row都是數值,中間逗號隔開。
多表查詢
- 交叉連接:笛卡爾乘積
- 內連接:
等值連接:讓表之間的字段以“等值”建立連接關系;
不等值連接
自然連接:去掉重復列的等值連接
自連接 - 外連接:
左外連接:
FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
右外連接
FROM tb1 RIGHT JOIN tb2 ON tb1.col=tb2.col - 子查詢:在查詢語句嵌套著查詢語句,性能較差
基於某語句的查詢結果再次進行的查詢- 用在WHERE子句中的子查詢
- 用於比較表達式中的子查詢;子查詢僅能返回單個值
SELECT Name,Age FROM students WHERE Age>(SELECT avg(Age)
FROM students); - 用於IN中的子查詢:子查詢應該單鍵查詢並返回一個或多個值從構成列表
SELECT Name,Age FROM students WHERE Age IN (SELECT Age
FROM teachers); - 用於EXISTS
- 用於FROM子句中的子查詢
使用格式:
SELECT tb_alias.col1,... FROM (SELECT clause) AS tb_alias WHERE Clause;
示例:
SELECT s.aage,s.ClassID FROM (SELECT avg(Age) AS aage,ClassID
FROM students WHERE ClassID IS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
- 聯合查詢:UNION
SELECT Name,Age FROM students UNION SELECT Name,Age FROM
teachers;
SELECT查詢語句執行順序,基本上也就是select命令的書寫順序:
註意點5(DQL多表):
- 第一種多表合並最簡單的方式就是縱向合並,不過要保證這兩個表的字段數(或者說用select選擇後的字段數)數量要一致;
- 其中的字段的datatype並沒有要求多個表都要一致,只需要字段數一樣就行
- 這兩個表最終的顯示效果的標頭是按照第一個表的select選擇的字段(的別名)來顯示的。
- 縱向合並的關鍵字為union,前後分別是select語句。,註意如果from關鍵字後多個表的表名如果有重名的(不同的數據庫中),要指明是哪個數據庫。用點.符號即可。
- 註意,union前後的select語句如果完全一樣(相當於自己union自己,兩個相同的),它並不會顯示兩遍結果出來,而僅僅是顯示一遍:因為union會自動合並內容完全一致的相同的row,具有自動去重功能;因此用這個功能可以直接自己連接自己來達到去重的效果。
- 橫向合並1,最簡單的就是一張表的所有記錄和另外一張表的所有記錄一一對應分別組合,兩張表的字段數相加合並,同時組合數為兩張表的記錄數的乘積
- 組合的命令為cross join, 和 union類似 ,不過它的命令前後不需要都加上select語句,它的前後只需要表的名字即可,例如:select * from TABLE1 corss join TABLE2 ;
- 橫向合並2:內連接(TABLE 1 inner join TABLE2 on Condition)
- 內連接就是用於兩張表相關聯的部分進行鏈接,這裏和cross join 不同的就是它的命令以及後面加上了on的條件限定(這裏on就類似之前的where,having)
- 比如 select * rom TABLE1 inner join TABLE2 on TABLE1.COLUME2 = TABLE2.COLUME1 [and | or等等更多條件] ;
- 如果只選定某些特定字段(如果不同名字段則不用標明表名,如果同名字段則要寫上表名,可用表名的別名)則可以在上面命令的基礎上 在TABL1和TABLE2後面加上別名,然後前面的*號就可以用別名後面加`.字段`的方式來引用不同的表的字段顯示了。
- 當然這個內連接也可以用 “select 字段 from TABLE1 [ALIAS1] ,TABLE2 [ALIAS2] where TABLE1.COLUME2 = TABLE2.COLUME1 ; ”的舊命令方式來代替。
- 橫向合並3:左外連接和右外連接(TABLE1 left outer join TABLE2 on Condition)
- 它倆的命令和內連接的區別就在於吧inner換成left outer 或right outer 其他都一樣
- 左外連接邏輯就是左邊的表格select選中的內容全部顯示出來,而右邊的表中select中只有符合後面on後面的判斷條件的record才會顯示出來,而那些沒有匹配到on條件的顯示出的左邊的表的record,在右邊的表的這些字段中全部用null填充顯示出來。
- 右外連接和左外鏈接剛好相反,右邊的表全部顯示,左邊的表匹配的顯示,剩余的補null(可以把表換個位置都用左外鏈接一樣的結果)
- 橫向合並4:左外鏈接取補和右外連接取補(左右外鏈接condition條件增加)
- 左外鏈接取補就是在左外鏈接的基礎性上,把on後面的condition中的符合條件的這一部分給去除掉即可,可以用某個字段為空的方式來取補(右外連接取補類似)
- 比如左外鏈接 select * rom TABLE1 left outer join TABLE2 on TABLE1.COLUME2 = TABLE2.COLUME1
- 然後對它進行條件取補 select * rom TABLE1 left outer join TABLE2 on TABLE1.COLUME2 = TABLE2.COLUME1 and TABLE2.COLUME1 is null
- 這樣就實現了左外鏈接取補
- 橫向合並5:完全外連接(左外連接 union 右外連接 )
- 它就是上面所寫的 ,只需要關鍵字 left 換成 right 然後 兩個select語句union即可,其他的條件等等全部相同。
- 註意它利用了union自動去重的功能
- 子查詢:多種方式,用where方式的時候結果必須為單值(看子查詢部分的例子)
- 橫向合並6:非交集部分(利用完全外連接和子查詢的方式)
- 先把完全外連接的select的表達式寫出來,把它看做為一張表,(用小括號括起來)同時給它起一個別名
- 然後再次select 語句,並利用where判斷條件把兩個表中內連接的部分去掉(可以利用!=符號方式)或者選中帶有空值的記錄(利用 or及is null ,用where創造兩個條件將兩邊的空值項篩選選出來)
- 上面寫的兩種方式是兩種思想,一種是利用完全外連接去掉內連接的之後想法,一種是利用左右外連接取補之後的並集想法來書寫where後面的限定條件
- 按照第二中上面寫的OR的想法:select * from (橫向合並5中的完全外連接)as a where a.TABLE2_COLUME1 is null or a.TABLE1_COLUME2 is null
- 這個過程中註意不要有重名,各個部分該用別名的就用別名。邏輯上沒有那麽復雜。
- 多對多的表(比如說學生表和科目表,每個學生可以報多個科目,且每個科目都有成績(這個成績在第三張表中),同時一個科目有多個學生可以報)
- 多對多的表都有第三張表來表示對應關系,在上面的例子中第三張表就是成績表,裏面記錄著"記錄的ID(主鍵)""學生的ID" "科目的ID" "科目的成績",以這種方式來表示學生表和科目表的對應關系
- 在這裏想要把成績表中的學生和科目顯示出來而不是ID號的話,就要用3張表的內連接方式了。
- 可以先連接兩張表的內連接 “select 字段 TABLE1 inner join TABLE2 on cONDITION1 ”
- 然後直接在後面再連接第三張表,而前面的select利用表的別名來進行選擇字段即可“select 字段 TABLE1 inner join TABLE2 on cONDITION1 inner join TABLE3 on Condition2”
- 或者也可以用另外的方式,就是先連接兩張表,然後小括號把它括起來作為一個表(view)來看待,之後再按照對表的操作方式對它進行操作即可,只是註意要多加別名,利用別名的方式來引用這個select命令結果的表
- 還有一種表的自內連接,比如說一個表三個字段為"員工ID""員工姓名""員工上司ID",想要把員工的上司的名字給顯示出來,利用自內連接,這也是一種也是很常見的方法。
- 把這張表直接當做兩張表來使用,一張看做員工表,一張看做上司表,利用內連接,別名進行鏈接即可
- select alias1.員工ID [員工號],alias1.員工姓名 [員工名], alias2.員工姓名 [上司名] from TABLE as alias1 inner join TABLE alias2 on alias1.員工上司ID = alias2.員工ID ;
- 上面命令中alias2第二張表看作是上司表,員工名字就是上司名,中括號內的為顯示出來的別名,為了更加清楚。
視圖
視圖:VIEW,虛表,保存有實表的查詢結果
- 創建方法:
CREATE VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION] - 查看視圖定義:SHOW CREATE VIEW view_name
- 刪除視圖:
DROP VIEW [IF EXISTS]
view_name [, view_name] ...
[RESTRICT | CASCADE]
註意:視圖中的數據事實上存儲於“基表”中,因此,其修改操作也會針對基表實現;其修改操作受基表限制
視圖註意點:
- 因為視圖創建完之後在數據庫中就像真的表一般無法區分,(此時當然也不可能用show create view view_name的方式來查看,因為不知道是view 還是 table)
這時候只可以用 show table status like ‘view_name‘\G; 的方式來判斷這個表到底是視圖還是表格了。 - 視圖可以當做是一個復雜的查詢語句的別名,可以把內連接的查詢結果創建一個視圖,這樣就不用每次輸入很長的的命令來進行內連接查詢了。
- 對視圖的修改如果修改成功了,則對應的原表也會相應的修改;不過對視圖的修改有很多要求,比如必須要是單表,不能有聚合函數等等限制,詳細更多要求以後再研究。
30.3. MySQL四種語句操作,SQL語法等簡介