MySql的前戲
在學習Mysql以前,咱們先來想一下一開始作的登陸註冊案例,當時咱們把用戶的信息保存到一個文件中:css
#用戶名 |密碼
root|123321
alex|123123
上面文件內容的規則是我本身定義的,你要想用我這個程序,必須按照個人規則去執行,但凡不是這個規則,就沒有交流的餘地。html
在一開始的時候文件格式的規定是沒有規範的,後面學到模塊的時候逐漸知道了目錄規則,咱們會把文件放到db目錄下。node
相似下面目錄結構:python
對於上面db目錄中,是能夠存放多個文件的,而且文件中能夠有多行數據。mysql
那麼問你們一個問題,若是說上面那個軟件是我寫好的,在一臺服務器或者一臺機器上安裝了我寫好的軟件。redis
如今有張三和李四兩我的都安裝了我這個軟件,張三註冊了一個用戶,李四也註冊了一個用戶,那麼本身註冊的用戶應該是本身用的。那麼這兩個用戶是不共享的,算法
因此這個軟件證實我寫的不太好,它不能共享,這種相似單機的軟件是很差的。sql
而後呢,我如今將我寫的這個軟件中目錄修改一下,將db目錄移除。如今將單機程序(本身的DB)改變成也是單機程序(公用DB)。mongodb
那麼以前給你們介紹過,凡是交互操做,是離不開scoket的,那麼如今我這邊有個公用DB和一個scoket服務端,而後在張三和李四那邊有scoket客戶端。張三和李四此時輸入用戶名和密碼,如今我這邊scoket服務端某個目錄接收用戶輸入的用戶名和密碼,看一下該用戶名存在不存在,若是存在返回true,若是不存在返回false。也就是說重點的內容咱們把db目錄放到某臺服務器上。數據庫
那麼上面這個例子呢,其實就給你們慢慢的引出來mysql了,mysql呢其實就一個軟件,這個軟件安裝到某臺電腦上或者某臺服務器上,那麼如今只要我告訴它建立一個文件目錄或者建立文件,那麼mysql就自動幫咱們建立了,好比說咱們再在文件中添加一條數據,那麼它也幫咱們完成。
總結一句話:其實mysql就是用於管理咱們的文件的一個軟件。
那麼對於mysql這個軟件來講有兩個軟件
---服務器軟件
- socket服務端
- 本地文件操做
- 解析指令(mysql語句)
---客戶端軟件
- socket客戶端
- 發送指令
- 解析指令(mysql語句)
解釋:
對於服務器軟件中的socket服務器是一直開着,客戶端得須要鏈接,而且還有建立文件、刪除文件等等的操做
對於客戶端軟件中的scoket客戶端,咱們得須要發送指令去命令scoket服務端對文件進行操做。
你們應該知道ftp的項目,上傳項目和下載項目的命令是不同的。那麼對於mysql中的客戶端和服務端也會有些指令的操做,那麼在這兩個端中應該是有解析指令的過程,這個指令只有mysql這個軟件知道,這種指令就是mysql語句。
再想一想咱們寫的html、css、js.這些比如就是咱們客戶端寫好的語法,而後瀏覽器充當了服務端的角色去解析咱們的的語法,最後來渲染出來結果。
接下來咱們要學習這些技能:
- 安裝 服務端和客戶端
- 鏈接
- 學習SOL語句規則:命令服務端作任何的操做
什麼是數據(Data)
描述事物的符號記錄稱爲數據,描述事物的符號既能夠是數字,也能夠是文字、圖片,圖像、聲音、語言等,數據由多種表現形式,它們均可以通過數字化後存入計算機
在計算機中描述一個事物,就須要抽取這一事物的典型特徵,組成一條記錄,就至關於文件裏的一行內容,如:
1 xiaomage,male,18,1999,山東,計算機系,2017,oldboy
單純的一條記錄並無任何意義,若是咱們按逗號做爲分隔,依次定義各個字段的意思,至關於定義表的標題
這樣經過表格咱們很清楚的知道了某人的詳細信息。
什麼是數據庫(DataBase,簡稱DB)
數據庫即存放數據的倉庫,只不過這個倉庫是在計算機存儲設備上,並且數據是按必定的格式存放的
過去人們將數據存放在文件櫃裏,如今數據量龐大,已經再也不適用
數據庫是長期存放在計算機內、有組織、可共享的數據便可。
數據庫中的數據按必定的數據模型組織、描述和儲存,具備較小的冗餘度、較高的數據獨立性和易擴展性,並可爲各類 用戶共享
什麼是數據庫管理系統(DataBase Management System)
在瞭解了Data與DB的概念後,如何科學地組織和存儲數據,如何高效獲取和維護數據成了關鍵
這就用到了一個系統軟件---數據庫管理系統
如MySQL、Oracle、SQLite、Access、MS SQL Server
mysql主要用於大型門戶,例如搜狗、新浪等,它主要的優點就是開放源代碼,由於開放源代碼這個數據庫是免費的,他如今是甲骨文公司的產品。
oracle主要用於銀行、鐵路、飛機場等。該數據庫功能強大,軟件費用高。也是甲骨文公司的產品。
sql server是微軟公司的產品,主要應用於大中型企業,如聯想、方正等。
數據庫服務器、數據管理系統、數據庫、表與記錄的關係(重點理解!!!)
記錄:1 xxx 324245234 22(多個字段的信息組成一條記錄,即文件中的一行內容)
表:student,scholl,class_list(即文件)
數據庫:oldboy_stu(即文件夾)
數據庫管理系統:如mysql(是一個軟件)
數據庫服務器:一臺計算機(對內存要求比較高)
總結:
數據庫服務器-:運行數據庫管理軟件
數據庫管理軟件:管理-數據庫
數據庫:即文件夾,用來組織文件/表
表:即文件,用來存放多行內容/多條記錄
本節掌握內容:
-
mysql的安裝、啓動
-
mysql破解密碼
-
統一字符編碼
MySQL是一個關係型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下公司。MySQL 最流行的關係型數據庫管理系統,在 WEB 應用方面MySQL是最好的 RDBMS (Relational Database Management System,關係數據庫管理系統) 應用軟件之一。
mysql是什麼?
mysql就是一個基於socket編寫的C/S架構的軟件
數據庫管理軟件分類
分兩大類:
關係型:如sqllite,db2,oracle,access,sql server,MySQL,注意:sql語句通用
非關係型:mongodb,redis,memcache
能夠簡單的理解爲:
關係型數據庫須要有表結構
非關係型數據庫是key-value存儲的,沒有表結構
mysql的下載安裝
想要使用MySQL來存儲並保存數據,則須要作幾件事情:
a. 安裝MySQL服務端
b. 安裝MySQL客戶端
b. 【客戶端】鏈接【服務端】
c. 【客戶端】發送命令給【服務端MySQL】服務的接受命令並執行相應操做(增刪改查等)
下載地址:
window版本
一、官網去下載
二、針對操做系統的不一樣下載不一樣的版本
3.解壓
若是想要讓MySQL安裝在指定目錄,那麼就將解壓後的文件夾移動到指定目錄,如:C:\mysql-5.6.40-winx64
4.添加環境變量
【右鍵計算機】--》【屬性】--》【高級系統設置】--》【高級】--》【環境變量】--》【在第二個內容框中找到 變量名爲Path 的一行,雙擊】 --> 【將MySQL的bin目錄路徑追加到變值值中,用 ; 分割】
5.初始化
1
|
mysqld
-
-
initialize
-
insecure
|
6.啓動mysql服務
7.啓動mysql客戶端並鏈接mysql服務端(新開一個cmd窗口)
mysql -u root -p # 鏈接MySQL服務器
上一步解決了一些問題,但不夠完全,由於在執行【mysqd】啓動MySQL服務器時,當前終端會被hang住,那麼作一下設置便可解決此問題,即將MySQL服務製做成windows服務
注意:--install前,必須用mysql啓動命令的絕對路徑
# 製做MySQL的Windows服務,在終端執行此命令:
"c:\mysql-5.6.40-winx64\bin\mysqld" --install
# 移除MySQL的Windows服務,在終端執行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --remove
註冊成服務以後,之後再啓動和關閉MySQL服務時,僅需執行以下命令:
# 啓動MySQL服務
net start mysql
# 關閉MySQL服務
net stop mysql
windows下登陸設置密碼
打開終端,輸入mysql
輸入mysql提供的函數:select user(); # 查看當前登陸的帳號
當前登陸的默認帳號爲ODBC@localhost
若是想切到root帳號登陸
執行命令:
再查看當前用戶:
管理員爲root(擁有最高權限,管理員帳號),密碼爲空,以無密碼的方式登陸了管理員帳號,是很是危險的一件事情,因此要爲管理員帳號設置密碼
設置管理員root帳號密碼爲123
C:\Users\mjj>mysqladmin -uroot -p password "123" #設置初始密碼 因爲原密碼爲空,所以-p能夠不用
ps:⚠️不用管它。翻譯爲:在命令行界面使用密碼不安全,暴露在終端當中。
而後再登陸帳號,不輸入密碼則會出現以下結果:
再次執行以下操做:
再查看一下當前登陸的帳號:
若是想將原始密碼123,設置新密碼爲456
C:\Users\mjj>mysqladmin -uroot -p"123" password "456" #修改mysql密碼,由於已經有密碼了,因此必須輸入原密碼才能設置新密碼
依次執行以下操做:
mysql -uroot -p456
select user();
密碼忘記——破解密碼
跳過受權方式,直接登陸!!
0.以管理員身份打開cmd
2.停掉mysql服務端
C:\WINDOWS\system32>net stop mysql
MySQL 服務正在中止.
MySQL 服務已成功中止。
3.執行以下命令跳過受權表
#跳過受權表
C:\WINDOWS\system32>mysqld --skip-grant-tables
2018-06-09 17:12:38 0 [Warning] Insecure configuration for --secure-file-priv: Current value does not restrict location of generated files. Consider setting it to a valid, non-empty path.
2018-06-09 17:12:38 0 [Note] mysqld (mysqld 5.6.40) starting as process 6052 ...4.
4.再次查看
5. 如今能夠任意的更改密碼,執行以下命令
update mysql.user set authentication_string =password('') where User='root';
6.刷新權限,執行命令
7.退出mysql。執行命令:exit,
8.讓用戶去加載權限,以管理員身份進入cmd,查看當前mysql進程
9.殺死當前的進程,執行以下命令
taskkill /F /PID 6052 # 殺死當前的進程pid
10.再次執行以下操做,還原
統一字符編碼
進入mysql客戶端,執行\s
爲了統一字符編碼,請執行以下操做:
(1)my.ini文件是mysql的配置文件,
在C:\mysql-5.6.40-winx64文件下建立my.ini文件
(2)將以下代碼拷貝保存。
#mysql5.5以上:修改方式爲
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
(3)以管理員身份重啓服務,執行以下命令
C:\Windows\system32>net stop MySQL
MySQL 服務正在中止..
MySQL 服務已成功中止。
C:\Windows\system32>net start MySQL
MySQL 服務正在啓動 .
MySQL 服務已經啓動成功。
(4)在cmd中輸入mysql進入mysql環境,執行\s,顯示以下信息,表示成功
本節課先對mysql的基本語法初體驗。
操做文件夾(庫)
增
create database db1 charset utf8;
查
# 查看當前建立的數據庫
show create database db1;
# 查看全部的數據庫
show databases;
改
alter database db1 charset gbk;
刪
操做文件(表)
use db1; #切換文件夾
select database(); #查看當前所在文件夾
增
create table t1(id int,name char);
查
#查看當前的這張t1表
show create table t1;
# 查看全部的表
show tables;
# 查看錶的詳細信息
desc t1;
改
# modify修改的意思
alter table t1 modify name char(6);
# 改變name爲大寫的NAME
alter table t1 change name NAMA char(7);
刪
操做文件內容(記錄)
增
# 插入一條數據,規定id,name數據leilei
insert t1(id,name) values(1,"mjj01"),(2,"mjj02"),(3,"mjj03");
查
select id from db1.t1;
select id,name from db1.t1;
select * from db1.t1;
改
update db1.t1 set name='zhangsan';
update db1.t1 set name='alex' where id=2;
刪
delete from t1;
delete from t1 where id=2;
本節重點:
1、系統數據庫
執行以下命令,查看系統庫
nformation_schema: 虛擬庫,不佔用磁盤空間,存儲的是數據庫啓動後的一些參數,如用戶表信息、列信息、權限信息、字符信息等
performance_schema: MySQL 5.5開始新增一個數據庫:主要用於收集數據庫服務器性能參數,記錄處理查詢請求時發生的各類事件、鎖等現象
mysql: 受權庫,主要存儲系統用戶的權限信息
test: MySQL數據庫系統自動建立的測試數據庫
2、建立數據庫
一、求救語法:
二、建立數據庫語法
CREATE DATABASE 數據庫名 charset utf8;
三、數據庫命名規則:
能夠由字母、數字、下劃線、@、#、$
區分大小寫
惟一性
不能使用關鍵字如 create select
不能單獨使用數字
最長128位
# 基本上跟python或者js的命名規則同樣
3、數據庫相關操做
#查看數據庫
show databases;
#查看當前庫
show create database db1;
#查看所在的庫
select database();
#選擇數據庫
use 數據庫名
#刪除數據庫
DROP DATABASE 數據庫名;
# 修改數據庫
alter database db1 charset utf8;
4、瞭解內容
SQL語言主要用於存取數據、查詢數據、更新數據和管理關係數據庫系統,SQL語言由IBM開發。SQL語言分爲3種類型:
1、DDL語句 數據庫定義語言: 數據庫、表、視圖、索引、存儲過程,例如CREATE DROP ALTER
2、DML語句 數據庫操縱語言: 插入數據INSERT、刪除數據DELETE、更新數據UPDATE、查詢數據SELECT
3、DCL語句 數據庫控制語言: 例如控制用戶的訪問權限GRANT、REVOKE
本節掌握
1、存儲引擎(瞭解)
前幾節咱們知道mysql中創建的庫===》文件夾,庫中的表====》文件
現實生活中咱們用來存儲數據的文件有不一樣的類型,每種文件類型對應各自不一樣的處理機制:好比處理文本用txt類型,處理表格用excel,處理圖片用png等
數據庫中的表也應該有不一樣的類型,表的類型不一樣,會對應mysql不一樣的存取機制,表類型又稱爲存儲引擎。
ps: 存儲引擎說白了就是如何存儲數據、如何爲存儲的數據創建索引和如何更新、查詢數據等技術的實現方法。由於在關係數據庫中數據的存儲是以表的形式存儲的,因此存儲引擎也能夠稱爲表類型(即存儲和操做此表的類型)
在Oracle 和SQL Server等數據庫中只有一種存儲引擎,全部數據存儲管理機制都是同樣的。而MySql
數據庫提供了多種存儲引擎。用戶能夠根據不一樣的需求爲數據表選擇不一樣的存儲引擎,用戶也能夠根據
本身的須要編寫本身的存儲引擎
SQL 解析器、SQL 優化器、緩衝池、存儲引擎等組件在每一個數據庫中都存在,但不是每 個數據庫都有這麼多存儲引擎。MySQL 的插件式存儲引擎可讓存儲引擎層的開發人員設 計他們但願的存儲層,例如,有的應用須要知足事務的要求,有的應用則不須要對事務有這 麼強的要求 ;有的但願數據能持久存儲,有的只但願放在內存中,臨時並快速地提供對數據 的查詢。
2、mysql支持的存儲引擎
mysql> show engines\G;# 查看全部支持的引擎
mysql> show variables like 'storage_engine%'; # 查看正在使用的存儲引擎
一、InnoDB 存儲引擎
支持事務,其設計目標主要面向聯機事務處理(OLTP)的應用。其
特色是行鎖設計、支持外鍵,並支持相似 Oracle 的非鎖定讀,即默認讀取操做不會產生鎖。 從 MySQL 5.5.8 版本開始是默認的存儲引擎。
InnoDB 存儲引擎將數據放在一個邏輯的表空間中,這個表空間就像黑盒同樣由 InnoDB 存儲引擎自身來管理。從 MySQL 4.1(包括 4.1)版本開始,能夠將每一個 InnoDB 存儲引擎的 表單獨存放到一個獨立的 ibd 文件中。此外,InnoDB 存儲引擎支持將裸設備(row disk)用 於創建其表空間。
InnoDB 經過使用多版本併發控制(MVCC)來得到高併發性,而且實現了 SQL 標準 的 4 種隔離級別,默認爲 REPEATABLE 級別,同時使用一種稱爲 netx-key locking 的策略來 避免幻讀(phantom)現象的產生。除此以外,InnoDB 存儲引擎還提供了插入緩衝(insert buffer)、二次寫(double write)、自適應哈希索引(adaptive hash index)、預讀(read ahead) 等高性能和高可用的功能。
對於表中數據的存儲,InnoDB 存儲引擎採用了彙集(clustered)的方式,每張表都是按 主鍵的順序進行存儲的,若是沒有顯式地在表定義時指定主鍵,InnoDB 存儲引擎會爲每一 行生成一個 6 字節的 ROWID,並以此做爲主鍵。
InnoDB 存儲引擎是 MySQL 數據庫最爲經常使用的一種引擎,Facebook、Google、Yahoo 等 公司的成功應用已經證實了 InnoDB 存儲引擎具有高可用性、高性能以及高可擴展性。對其 底層實現的掌握和理解也須要時間和技術的積累。若是想深刻了解 InnoDB 存儲引擎的工做 原理、實現和應用,能夠參考《MySQL 技術內幕:InnoDB 存儲引擎》一書。
二、MyISAM 存儲引擎
不支持事務、表鎖設計、支持全文索引,主要面向一些 OLAP 數 據庫應用,在 MySQL 5.5.8 版本以前是默認的存儲引擎(除 Windows 版本外)。數據庫系統 與文件系統一個很大的不一樣在於對事務的支持,MyISAM 存儲引擎是不支持事務的。究其根 本,這也並不難理解。用戶在全部的應用中是否都須要事務呢?在數據倉庫中,若是沒有 ETL 這些操做,只是簡單地經過報表查詢還須要事務的支持嗎?此外,MyISAM 存儲引擎的 另外一個不同凡響的地方是,它的緩衝池只緩存(cache)索引文件,而不緩存數據文件,這與 大多數的數據庫都不相同。
三、NDB 存儲引擎
年,MySQL AB 公司從 Sony Ericsson 公司收購了 NDB 存儲引擎。 NDB 存儲引擎是一個集羣存儲引擎,相似於 Oracle 的 RAC 集羣,不過與 Oracle RAC 的 share everything 結構不一樣的是,其結構是 share nothing 的集羣架構,所以能提供更高級別的 高可用性。NDB 存儲引擎的特色是數據所有放在內存中(從 5.1 版本開始,能夠將非索引數 據放在磁盤上),所以主鍵查找(primary key lookups)的速度極快,而且可以在線添加 NDB 數據存儲節點(data node)以便線性地提升數據庫性能。因而可知,NDB 存儲引擎是高可用、 高性能、高可擴展性的數據庫集羣系統,其面向的也是 OLTP 的數據庫應用類型。
四、Memory 存儲引擎
正如其名,Memory 存儲引擎中的數據都存放在內存中,數據庫重 啓或發生崩潰,表中的數據都將消失。它很是適合於存儲 OLTP 數據庫應用中臨時數據的臨時表,也能夠做爲 OLAP 數據庫應用中數據倉庫的維度表。Memory 存儲引擎默認使用哈希 索引,而不是一般熟悉的 B+ 樹索引。
五、Infobright 存儲引擎
第三方的存儲引擎。其特色是存儲是按照列而非行的,所以很是 適合 OLAP 的數據庫應用。其官方網站是 http://www.infobright.org/,上面有很多成功的數據 倉庫案例可供分析。
六、NTSE 存儲引擎
網易公司開發的面向其內部使用的存儲引擎。目前的版本不支持事務, 但提供壓縮、行級緩存等特性,不久的未來會實現面向內存的事務支持。
七、BLACKHOLE
黑洞存儲引擎,能夠應用於主備複製中的分發主庫。
MySQL 數據庫還有不少其餘存儲引擎,上述只是列舉了最爲經常使用的一些引擎。若是 你喜歡,徹底能夠編寫專屬於本身的引擎,這就是開源賦予咱們的能力,也是開源的魅 力所在。
指定表類型/存儲引擎
create table t1(id int)engine=innodb;# 默認不寫就是innodb
小練習:
建立四張表,分別使用innodb,myisam,memory,blackhole存儲引擎,進行插入數據測試
create table t1(id int)engine=innodb;
create table t2(id int)engine=myisam;
create table t3(id int)engine=memory;
create table t4(id int)engine=blackhole;
查看data文件下db1數據庫中的文件:
#.frm是存儲數據表的框架結構
# .ibd是mysql數據文件
#.MYD是MyISAM表的數據文件的擴展名
#.MYI是MyISAM表的索引的擴展名
#發現後兩種存儲引擎只有表結構,無數據
#memory,在重啓mysql或者重啓機器後,表內數據清空
#blackhole,往表內插入任何數據,都至關於丟入黑洞,表內永遠不存記錄
3、表介紹
表至關於文件,表中的一條記錄就至關於文件的一行內容,不一樣的是,表中的一條記錄有對應的標題,稱爲表的字段
id,name,sex,age,birth稱爲字段,其他的,一行內容稱爲一條記錄
4、建立表
語法:
create table 表名(
字段名1 類型[(寬度) 約束條件],
字段名2 類型[(寬度) 約束條件],
字段名3 類型[(寬度) 約束條件]
);
#注意:
1. 在同一張表中,字段名是不能相同
2. 寬度和約束條件可選
3. 字段名和類型是必須的
1.建立數據庫
create database db2 charset utf8;
2.使用數據庫
3.建立a1表
create table a1(
id int,
name varchar(50),
age int(3)
);
4.插入表的記錄
insert into a1 values
(1,'mjj',18),
(2,'wusir',28);
ps:以;做爲mysql的結束語
5.查詢表的數據和結構
(1)查詢a1表中的存儲數據
mysql> select * from a1;
+------+-------+------+
| id | name | age |
+------+-------+------+
| 1 | mjj | 18 |
| 2 | wusir | 28 |
+------+-------+------+
2 rows in set (0.02 sec)
mysql>
(2)查看a1表的結構
mysql> desc a1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
| age | int(3) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.16 sec)
(3)查看錶的詳細結構
mysql> show create table a1\G;
*************************** 1. row ***************************
Table: a1
Create Table: CREATE TABLE `a1` (
`id` int(11) DEFAULT NULL,
`name` varchar(50) DEFAULT NULL,
`age` int(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
6.複製表
(1)新建立一個數據庫db3
mysql> create database db3 charset utf8;
Query OK, 1 row affected (0.00 sec)
(2)使用db3
mysql> use db3;
Database changed
#這是上個建立的db2數據庫中的a1表
mysql> select * from db2.a1;
+------+-------+------+
| id | name | age |
+------+-------+------+
| 1 | mjj | 18 |
| 2 | wusir | 28 |
+------+-------+------+
(3)複製db2.a1的表結構和記錄
# 這就是複製表的操做(既複製了表結構,又複製了記錄)
mysql> create table b1 select * from db2.a1;
Query OK, 2 rows affected (0.03 sec)
(4)查看db3.b1中的數據和表結構
#再去查看db3文件夾下的b1表發現 跟db2文件下的a1表數據同樣
mysql> select * from db3.b1;
+------+-------+------+
| id | name | age |
+------+-------+------+
| 1 | mjj | 18 |
| 2 | wusir | 28 |
+------+-------+------+
2 rows in set (0.00 sec)
ps1:若是隻要表結構,不要記錄
#在db2數據庫下新建立一個b2表,給一個where條件,條件要求不成立,條件爲false,只拷貝表結構
mysql> create table b2 select * from db2.a1 where 1>5;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
查看錶結構:
# 查看錶結構
mysql> desc b2;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
| age | int(3) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.02 sec)
#查看錶結構中的數據,發現是空數據
mysql> select * from b2;
Empty set (0.00 sec)
ps2:還有一種作法,使用like(只拷貝表結構,不拷貝記錄)
mysql> create table b3 like db2.a1;
Query OK, 0 rows affected (0.01 sec)
mysql> desc b3;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
| age | int(3) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.02 sec)
mysql> select * from db3.b3;
Empty set (0.00 sec)
7.刪除表:
介紹
存儲引擎決定了表的類型,而表內存放的數據也要有不一樣的類型,每種數據類型都有本身的寬度,但寬度是可選的
詳細參考連接:http://www.runoob.com/mysql/mysql-data-types.html
mysql經常使用數據類型歸納:
#1. 數字:
整型:tinyinit int bigint
小數:
float :在位數比較短的狀況下不精準
double :在位數比較長的狀況下不精準
0.000001230123123123
存成:0.000001230000
decimal:(若是用小數,則用推薦使用decimal)
精準
內部原理是以字符串形式去存
#2. 字符串:
char(10):簡單粗暴,浪費空間,存取速度快
root存成root000000
varchar:精準,節省空間,存取速度慢
sql優化:建立表時,定長的類型往前放,變長的日後放
好比性別 好比地址或描述信息
>255個字符,超了就把文件路徑存放到數據庫中。
好比圖片,視頻等找一個文件服務器,數據庫中只存路徑或url。
#3. 時間類型:
最經常使用:datetime
#4. 枚舉類型與集合類型
1、數值類型
整數類型:TINYINT SMALLINT MEDIUMINT INT BIGINT
做用:存儲年齡,等級,id,各類號碼等
========================================
tinyint[(m)] [unsigned] [zerofill]
小整數,數據類型用於保存一些範圍的整數數值範圍:
有符號:
-128 ~ 127
無符號:
~ 255
PS: MySQL中無布爾值,使用tinyint(1)構造。
========================================
int[(m)][unsigned][zerofill]
整數,數據類型用於保存一些範圍的整數數值範圍:
有符號:
-2147483648 ~ 2147483647
無符號:
~ 4294967295
========================================
bigint[(m)][unsigned][zerofill]
大整數,數據類型用於保存一些範圍的整數數值範圍:
有符號:
-9223372036854775808 ~ 9223372036854775807
無符號:
~ 18446744073709551615
驗證1:有符號和無符號tinyint
============有符號tinyint==============
# 建立數據庫db4
create database db4 charset utf8;
# 切換到當前db4數據庫
mysql> use db4;
# 建立t1 規定x字段爲tinyint數據類型(默認是有符號的)
mysql> create table t1(x tinyint);
# 驗證,插入-1這個數
mysql> insert into t1 values(-1);
# 查詢 表記錄,查詢成功(證實默認是有符號類型)
mysql> select * from t1;
+------+
| x |
+------+
| -1 |
+------+
#執行以下操做,會發現報錯。由於有符號範圍在(-128,127)
mysql> insert into t1 values(-129),(128);
ERROR 1264 (22003): Out of range value for column 'x' at row 1
============無符號tinyint==============
# 建立表時定義記錄的字符爲無符號類型(0,255) ,使用unsigned
mysql> create table t2(x tinyint unsigned);
# 報錯,超出範圍
mysql> insert into t2 values(-129);
ERROR 1264 (22003): Out of range value for column 'x' at row 1
# 插入成功
mysql> insert into t2 values(255);
Query OK, 1 row affected (0.00 sec)
驗證2:int類型後面的存儲是顯示寬度,而不是存儲寬度
mysql> create table t3(id int(1) unsigned);
#插入255555記錄也是能夠的
mysql> insert into t3 values(255555);
mysql> select * from t3;
+--------+
| id |
+--------+
| 255555 |
+--------+
ps:以上操做還不可以驗證,再來一張表驗證用zerofill 用0填充
# zerofill 用0填充
mysql> create table t4(id int(5) unsigned zerofill);
mysql> insert into t4 value(1);
Query OK, 1 row affected (0.00 sec)
#插入的記錄是1,可是顯示的寬度是00001
mysql> select * from t4;
+-------+
| id |
+-------+
| 00001 |
+-------+
1 row in set (0.00 sec)
注意:爲該類型指定寬度時,僅僅只是指定查詢結果的顯示寬度,與存儲範圍無關,存儲範圍以下
其實咱們徹底不必爲整數類型指定顯示寬度,使用默認的就能夠了
默認的顯示寬度,都是在最大值的基礎上加1
int的存儲寬度是4個Bytes,即32個bit,即2**32
無符號最大值爲:4294967296-1
有符號最大值:2147483648-1
有符號和無符號的最大數字須要的顯示寬度均爲10,而針對有符號的最小值則須要11位才能顯示徹底,因此int類型默認的顯示寬度爲11是很是合理的
最後:整形類型,其實沒有必要指定顯示寬度,使用默認的就ok
2、浮點型
定點數類型: DEC等同於DECIMAL
浮點類型:FLOAT DOUBLE
做用:存儲薪資、身高、體重、體質參數等
語法:
-------------------------FLOAT-------------------
FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]
#參數解釋:單精度浮點數(非準確小數值),M是全長,D是小數點後個數。M最大值爲255,D最大值爲30
#有符號:
-3.402823466E+38 to -1.175494351E-38,
1.175494351E-38 to 3.402823466E+38
#無符號:
1.175494351E-38 to 3.402823466E+38
#精確度:
**** 隨着小數的增多,精度變得不許確 ****
-------------------------DOUBLE-----------------------
DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]
#參數解釋: 雙精度浮點數(非準確小數值),M是全長,D是小數點後個數。M最大值爲255,D最大值爲30
#有符號:
-1.7976931348623157E+308 to -2.2250738585072014E-308
2.2250738585072014E-308 to 1.7976931348623157E+308
#無符號:
2.2250738585072014E-308 to 1.7976931348623157E+308
#精確度:
****隨着小數的增多,精度比float要高,但也會變得不許確 ****
======================================
--------------------DECIMAL------------------------
decimal[(m[,d])] [unsigned] [zerofill]
#參數解釋:準確的小數值,M是整數部分總個數(負號不算),D是小數點後個數。 M最大值爲65,D最大值爲30。
#精確度:
**** 隨着小數的增多,精度始終準確 ****
對於精確數值計算時須要用此類型
decaimal可以存儲精確值的緣由在於其內部按照字符串存儲。
驗證三種類型建表:
#1驗證FLOAT類型建表:
mysql> create table t5(x float(256,31));
ERROR 1425 (42000): Too big scale 31 specified for column 'x'. Maximum is 30.
mysql> create table t5(x float(256,30));
ERROR 1439 (42000): Display width out of range for column 'x' (max = 255)
mysql> create table t5(x float(255,30)); #建表成功
Query OK, 0 rows affected (0.03 sec)
#2驗證DOUBLE類型建表:
mysql> create table t6(x double(255,30)); #建表成功
Query OK, 0 rows affected (0.03 sec)
#3驗證deimal類型建表:
mysql> create table t7(x decimal(66,31));
ERROR 1425 (42000): Too big scale 31 specified for column 'x'. Maximum is 30.
mysql> create table t7(x decimal(66,30));
ERROR 1426 (42000): Too big precision 66 specified for column 'x'. Maximum is 65.
mysql> create table t7(x decimal(65,30)); #建表成功
Query OK, 0 rows affected (0.00 sec)
驗證三種類型的精度:
# 分別對三張表插入相應的記錄
mysql> insert into t5 values(1.1111111111111111111111111111111);#小數點後31個1
Query OK, 1 row affected (0.01 sec)
mysql> insert into t6 values(1.1111111111111111111111111111111);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t7 values(1.1111111111111111111111111111111);
Query OK, 1 row affected, 1 warning (0.00 sec)
# 查詢結果
mysql> select * from t5; #隨着小數的增多,精度開始不許確
+----------------------------------+
| x |
+----------------------------------+
| 1.111111164093017600000000000000 |
+----------------------------------+
1 row in set (0.00 sec)
mysql> select * from t6; #精度比float要準確點,但隨着小數的增多,一樣變得不許確
+----------------------------------+
| x |
+----------------------------------+
| 1.111111111111111200000000000000 |
+----------------------------------+
1 row in set (0.00 sec)
mysql> select * from t7; #精度始終準確,d爲30,因而只留了30位小數
+----------------------------------+
| x |
+----------------------------------+
| 1.111111111111111111111111111111 |
+----------------------------------+
1 row in set (0.00 sec)
3、日期類型
DATE TIME DATETIME TIMESTAMP YEAR
做用:存儲用戶註冊時間,文章發佈時間,員工入職時間,出生時間,過時時間等
語法:
YEAR
YYYY(1901/2155)
DATE
YYYY-MM-DD(1000-01-01/9999-12-31)
TIME
HH:MM:SS('-838:59:59'/'838:59:59')
DATETIME
YYYY-MM-DD HH:MM:SS(1000-01-01 00:00:00/9999-12-31 23:59:59 Y)
TIMESTAMP
YYYYMMDD HHMMSS(1970-01-01 00:00:00/2037 年某時)
驗證:
一、year
mysql> create table t8(born_year year);#不管year指定何種寬度,最後都默認是year(4)
Query OK, 0 rows affected (0.03 sec)
#插入失敗,超出範圍(1901/2155)
mysql> insert into t8 values
-> (1900),
-> (1901),
-> (2155),
-> (2156);
ERROR 1264 (22003): Out of range value for column 'born_year' at row 1
mysql> select * from t8;
Empty set (0.01 sec)
mysql> insert into t8 values
-> (1905),
-> (2018);
Query OK, 2 rows affected (0.00 sec) #插入記錄成功
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t8;
+-----------+
| born_year |
+-----------+
| 1905 |
| 2018 |
+-----------+
2 rows in set (0.00 sec)
二、date、year、datetime
#建立t9表
mysql> create table t9(d date,t time,dt datetime);
Query OK, 0 rows affected (0.06 sec)
#查看錶的結構
mysql> desc t9;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| d | date | YES | | NULL | |
| t | time | YES | | NULL | |
| dt | datetime | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.14 sec)
# 調用mysql自帶的now()函數,獲取當前類型指定的時間 以下結構
mysql> insert into t9 values(now(),now(),now());
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select * from t9;
+------------+----------+---------------------+
| d | t | dt |
+------------+----------+---------------------+
| 2018-06-09 | 09:35:20 | 2018-06-09 09:35:20 |
+------------+----------+---------------------+
1 row in set (0.00 sec)
三、timestamp(瞭解便可)
mysql> create table t10(time timestamp);
Query OK, 0 rows affected (0.06 sec)
mysql> insert into t10 values();
Query OK, 1 row affected (0.00 sec)
mysql> insert into t10 values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t10;
+------+
| time |
+------+
| NULL |
| NULL |
+------+
mysql> insert into t10 values(now());
Query OK, 1 row affected (0.01 sec)
mysql> select * from t10;
+---------------------+
| time |
+---------------------+
| 2018-06-09 09:44:48 |
+---------------------+
1 row in set (0.01 sec)
datetime與timestamp的區別
在實際應用的不少場景中,MySQL的這兩種日期類型都可以知足咱們的須要,存儲精度都爲秒,但在某些狀況下,會展示出他們各自的優劣。
下面就來總結一下兩種日期類型的區別。
1.DATETIME的日期範圍是1001——9999年,TIMESTAMP的時間範圍是1970——2038年。
2.DATETIME存儲時間與時區無關,TIMESTAMP存儲時間與時區有關,顯示的值也依賴於時區。在mysql服務器,
操做系統以及客戶端鏈接都有時區的設置。
3.DATETIME使用8字節的存儲空間,TIMESTAMP的存儲空間爲4字節。所以,TIMESTAMP比DATETIME的空間利用率更高。
4.DATETIME的默認值爲null;TIMESTAMP的字段默認不爲空(not null),默認值爲當前時間(CURRENT_TIMESTAMP),
若是不作特殊處理,而且update語句中沒有指定該列的更新值,則默認更新爲當前時間。
注意事項
============注意啦,注意啦,注意啦===========
#1. 單獨插入時間時,須要以字符串的形式,按照對應的格式插入
#2. 插入年份時,儘可能使用4位值
#3. 插入兩位年份時,<=69,以20開頭,好比50, 結果2050
>=70,以19開頭,好比71,結果1971
create table t12(y year);
insert into t12 values (50),(71);
select * from t12;
+------+
| y |
+------+
| 2050 |
| 1971 |
+------+
綜合練習:
建立一張學生表(student),要求有id,姓名,出生年份,出生的年月日,進班的時間,以及來老男孩學習的如今具體時間。
mysql> create table student(
-> id int,
-> name varchar(20),
-> born_year year,
-> birth date,
-> class_time time,
-> reg_time datetime
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into student values
-> (1,'alex',"1995","1995-11-11","11:11:11","2017-11-11 11:11:11"),
-> (2,'egon',"1997","1997-12-12","12:12:12","2017-12-12 12:12:12"),
-> (3,'wsb',"1998","1998-01-01","13:13:13","2017-01-01 13:13:13");
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from student;
+------+------+-----------+------------+------------+---------------------+
| id | name | born_year | birth | class_time | reg_time |
+------+------+-----------+------------+------------+---------------------+
| 1 | alex | 1995 | 1995-11-11 | 11:11:11 | 2017-11-11 11:11:11 |
| 2 | egon | 1997 | 1997-12-12 | 12:12:12 | 2017-12-12 12:12:12 |
| 3 | wsb | 1998 | 1998-01-01 | 13:13:13 | 2017-01-01 13:13:13 |
+------+------+-----------+------------+------------+---------------------+
rows in set (0.00 sec)
本節重點
- 掌握char類型和varchar類型
- 掌握枚舉類型和集合類型
字符類型
#官網:https://dev.mysql.com/doc/refman/5.7/en/char.html
#注意:char和varchar括號內的參數指的都是字符的長度
#char類型:定長,簡單粗暴,浪費空間,存取速度快
字符長度範圍:0-255(一箇中文是一個字符,是utf8編碼的3個字節)
存儲:
存儲char類型的值時,會往右填充空格來知足長度
例如:指定長度爲10,存>10個字符則報錯,存<10個字符則用空格填充直到湊夠10個字符存儲
檢索:
在檢索或者說查詢時,查出的結果會自動刪除尾部的空格,除非咱們打開pad_char_to_full_length SQL模式(設置SQL模式:SET sql_mode = 'PAD_CHAR_TO_FULL_LENGTH';
查詢sql的默認模式:select @@sql_mode;)
#varchar類型:變長,精準,節省空間,存取速度慢
字符長度範圍:0-65535(若是大於21845會提示用其餘類型 。mysql行最大限制爲65535字節,字符編碼爲utf-8:https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html)
存儲:
varchar類型存儲數據的真實內容,不會用空格填充,若是'ab ',尾部的空格也會被存起來
強調:varchar類型會在真實數據前加1-2Bytes的前綴,該前綴用來表示真實數據的bytes字節數(1-2Bytes最大表示65535個數字,正好符合mysql對row的最大字節限制,即已經足夠使用)
若是真實的數據<255bytes則須要1Bytes的前綴(1Bytes=8bit 2**8最大表示的數字爲255)
若是真實的數據>255bytes則須要2Bytes的前綴(2Bytes=16bit 2**16最大表示的數字爲65535)
檢索:
尾部有空格會保存下來,在檢索或者說查詢時,也會正常顯示包含空格在內的內容
官網解釋以下:
驗證:
驗證以前瞭解兩個函數:
length():查看字節數
char_length():查看字符數
1.char填充空格來知足固定長度,可是在查詢時卻會很不要臉地刪除尾部的空格(裝做本身好像沒有浪費過空間同樣),而後修改sql_mode讓其現出原形。
# 建立t1表,分別指明字段x爲char類型,字段y爲varchar類型
mysql> create table t1(x char(5),y varchar(4));
Query OK, 0 rows affected (0.16 sec)
# char存放的是5個字符,而varchar存4個字符
mysql> insert into t1 values('你瞅啥 ','你瞅啥 ');
Query OK, 1 row affected (0.01 sec)
# 在檢索時char很不要臉地將本身浪費的2個字符給刪掉了,裝的好像本身沒浪費過空間同樣,而varchar很老實,存了多少,就顯示多少
mysql> select x,char_length(x),y,char_length(y) from t1;
+-----------+----------------+------------+----------------+
| x | char_length(x) | y | char_length(y) |
+-----------+----------------+------------+----------------+
| 你瞅啥 | 3 | 你瞅啥 | 4 |
+-----------+----------------+------------+----------------+
1 row in set (0.02 sec)
#略施小計,讓char現原形
mysql> SET sql_mode = 'PAD_CHAR_TO_FULL_LENGTH';
Query OK, 0 rows affected (0.00 sec)
#查看當前mysql的mode模式
mysql> select @@sql_mode;
+-------------------------+
| @@sql_mode |
+-------------------------+
| PAD_CHAR_TO_FULL_LENGTH |
+-------------------------+
1 row in set (0.00 sec)
#原形畢露了吧。。。。
mysql> select x,char_length(x) y,char_length(y) from t1;
+-------------+------+----------------+
| x | y | char_length(y) |
+-------------+------+----------------+
| 你瞅啥 | 5 | 4 |
+-------------+------+----------------+
1 row in set (0.00 sec)
# 查看字節數
#char類型:3箇中文字符+2個空格=11Bytes
#varchar類型:3箇中文字符+1個空格=10Bytes
mysql> select x,length(x),y,length(y) from t1;
+-------------+-----------+------------+-----------+
| x | length(x) | y | length(y) |
+-------------+-----------+------------+-----------+
| 你瞅啥 | 11 | 你瞅啥 | 10 |
+-------------+-----------+------------+-----------+
1 row in set (0.02 sec)
總結:
#經常使用字符串系列:char與varchar
注:雖然varchar使用起來較爲靈活,可是從整個系統的性能角度來講,char數據類型的處理速度更快,有時甚至能夠超出varchar處理速度的50%。所以,用戶在設計數據庫時應當綜合考慮各方面的因素,以求達到最佳的平衡
#其餘字符串系列(效率:char>varchar>text)
TEXT系列 TINYTEXT TEXT MEDIUMTEXT LONGTEXT
BLOB 系列 TINYBLOB BLOB MEDIUMBLOB LONGBLOB
BINARY系列 BINARY VARBINARY
text:text數據類型用於保存變長的大字符串,能夠組多到65535 (2**16 − 1)個字符。
mediumtext:A TEXT column with a maximum length of 16,777,215 (2**24 − 1) characters.
longtext:A TEXT column with a maximum length of 4,294,967,295 or 4GB (2**32 − 1) characters.
枚舉類型和集合類型
字段的值只能在給定範圍中選擇,如單選框,多選框
enum 單選 只能在給定的範圍內選一個值,如性別 sex 男male/女female
set 多選 在給定的範圍內能夠選擇一個或一個以上的值(愛好1,愛好2,愛好3...)
mysql> create table consumer(
-> id int,
-> name varchar(50),
-> sex enum('male','female','other'),
-> level enum('vip1','vip2','vip3','vip4'),#在指定範圍內,多選一
-> fav set('play','music','read','study') #在指定範圍內,多選多
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into consumer values
-> (1,'趙雲','male','vip2','read,study'),
-> (2,'趙雲2','other','vip4','play');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from consumer;
+------+---------+-------+-------+------------+
| id | name | sex | level | fav |
+------+---------+-------+-------+------------+
| 1 | 趙雲 | male | vip2 | read,study |
| 2 | 趙雲2 | other | vip4 | play |
+------+---------+-------+-------+------------+
2 rows in set (0.00 sec)
本節重點:
- not null 與 default
- unique
- primary
- auto_increment
- foreign key
1、介紹
約束條件與數據類型的寬度同樣,都是可選參數
做用:用於保證數據的完整性和一致性
主要分爲:
PRIMARY KEY (PK) #標識該字段爲該表的主鍵,能夠惟一的標識記錄
FOREIGN KEY (FK) #標識該字段爲該表的外鍵
NOT NULL #標識該字段不能爲空
UNIQUE KEY (UK) #標識該字段的值是惟一的
AUTO_INCREMENT #標識該字段的值自動增加(整數類型,並且爲主鍵)
DEFAULT #爲該字段設置默認值
UNSIGNED #無符號
ZEROFILL #使用0填充
說明:
#1. 是否容許爲空,默認NULL,可設置NOT NULL,字段不容許爲空,必須賦值
#2. 字段是否有默認值,缺省的默認值是NULL,若是插入記錄時不給字段賦值,此字段使用默認值
sex enum('male','female') not null default 'male'
#必須爲正值(無符號) 不容許爲空 默認是20
age int unsigned NOT NULL default 20
# 3. 是不是key
主鍵 primary key
外鍵 foreign key
索引 (index,unique...)
2、not null 與default
是否可空,null表示空,非字符串
not null - 不可空
null - 可空
默認值,建立列時能夠指定默認值,當插入數據時若是未主動設置,則自動添加默認值
create table tb1(
nid int not null defalut 2,
num int not null
);
驗證1:
mysql> create table t11(id int);# id字段默承認覺得空
Query OK, 0 rows affected (0.05 sec)
mysql> desc t11;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
row in set (0.03 sec)
mysql> insert into t11 values(); #給t11表插一個空的值
Query OK, 1 row affected (0.00 sec)
#查詢結果以下
mysql> select * from t11;
+------+
| id |
+------+
| NULL |
+------+
row in set (0.00 sec)
默認值能夠爲空
驗證2:
mysql> create table t12(id int not null);#設置字段id不爲空
Query OK, 0 rows affected (0.03 sec)
mysql> desc t12;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
+-------+---------+------+-----+---------+-------+
row in set (0.01 sec)
mysql> insert into t12 values();#不能插入空
ERROR 1364 (HY000): Field 'id' doesn't have a default value
設置not null,插入值時不能爲空
驗證3:
# 第一種狀況
mysql> create table t13(id int default 1);
Query OK, 0 rows affected (0.03 sec)
mysql> desc t13;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | | 1 | |
+-------+---------+------+-----+---------+-------+
row in set (0.01 sec)
mysql> insert into t13 values();
Query OK, 1 row affected (0.00 sec)
mysql> select * from t13;
+------+
| id |
+------+
| 1 |
+------+
row in set (0.00 sec)
# 第二種狀況
mysql> create table t14(id int not null default 2);
Query OK, 0 rows affected (0.02 sec)
mysql> desc t14;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | NO | | 2 | |
+-------+---------+------+-----+---------+-------+
row in set (0.01 sec)
mysql> select * from t14;
+----+
| id |
+----+
| 2 |
+----+
row in set (0.00 sec)
設置id字段有默認值後,則不管id字段是null仍是not null,均可以插入空,插入空默認填入default指定的默認值
小練習:
建立學生表student2,設置每一個字段的約束條件。
mysql> create table student2(
-> id int not null,
-> name varchar(50) not null,
-> age int(3) unsigned not null default 18,
-> sex enum('male','female') default 'male',
-> fav set('smoke','drink','tangtou') default 'drink,tangtou'
-> );
Query OK, 0 rows affected (0.01 sec)
# 只插入了not null約束條件的字段對應的值
mysql> insert into student2(id,name) values(1,'mjj');
Query OK, 1 row affected (0.00 sec)
# 查詢結果以下
mysql> select * from student2;
+----+------+-----+------+---------------+
| id | name | age | sex | fav |
+----+------+-----+------+---------------+
| 1 | mjj | 18 | male | drink,tangtou |
+----+------+-----+------+---------------+
1 row in set (0.00 sec)
三、unique
中文翻譯:不一樣的。在mysql中稱爲單列惟一
舉例說明:建立公司部門表(每一個公司都有惟一的一個部門)。
mysql> create table department(
-> id int,
-> name char(10)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into department values(1,'IT'),(2,'IT');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from department;
+------+------+
| id | name |
+------+------+
| 1 | IT |
| 2 | IT |
+------+------+
rows in set (0.00 sec)
# 發現: 同時插入兩個IT部門也是能夠的,但這是不合理的,因此咱們要設置name字段爲unique 解決這種不合理的現象。
驗證以前重複插入記錄的操做是可行的,可是不符合場景
接下來,使用約束條件unique,來對公司部門的字段進行設置。
#第一種建立unique的方式
#例子1:
create table department(
id int,
name char(10) unique
);
mysql> insert into department values(1,'it'),(2,'it');
ERROR 1062 (23000): Duplicate entry 'it' for key 'name'
#例子2:
create table department(
id int unique,
name char(10) unique
);
insert into department values(1,'it'),(2,'sale');
#第二種建立unique的方式
create table department(
id int,
name char(10) ,
unique(id),
unique(name)
);
insert into department values(1,'it'),(2,'sale');
聯合惟一:
# 建立services表
mysql> create table services(
-> id int,
-> ip char(15),
-> port int,
-> unique(id),
-> unique(ip,port)
-> );
Query OK, 0 rows affected (0.05 sec)
mysql> desc services;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | |
| ip | char(15) | YES | MUL | NULL | |
| port | int(11) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.01 sec)
#聯合惟一,只要兩列記錄,有一列不一樣,既符合聯合惟一的約束
mysql> insert into services values
-> (1,'192,168,11,23',80),
-> (2,'192,168,11,23',81),
-> (3,'192,168,11,25',80);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from services;
+------+---------------+------+
| id | ip | port |
+------+---------------+------+
| 1 | 192,168,11,23 | 80 |
| 2 | 192,168,11,23 | 81 |
| 3 | 192,168,11,25 | 80 |
+------+---------------+------+
3 rows in set (0.00 sec)
mysql> insert into services values (4,'192,168,11,23',80);
ERROR 1062 (23000): Duplicate entry '192,168,11,23-80' for key 'ip'
4.primary key
一個表中能夠:
單列作主鍵
多列作主鍵(複合主鍵)
約束:等價於 not null unique,字段的值不爲空且惟一
存儲引擎默認是(innodb):對於innodb存儲引擎來講,一張表必須有一個主鍵。
單列主鍵
# 建立t14表,爲id字段設置主鍵,惟一的不一樣的記錄
create table t14(
id int primary key,
name char(16)
);
insert into t14 values
(1,'xiaoma'),
(2,'xiaohong');
mysql> insert into t14 values(2,'wxxx');
ERROR 1062 (23000): Duplicate entry '6' for key 'PRIMARY'
# not null + unique的化學反應,至關於給id設置primary key
create table t15(
id int not null unique,
name char(16)
);
mysql> create table t15(
-> id int not null unique,
-> name char(16)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> desc t15;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | char(16) | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.02 sec)
複合主鍵
create table t16(
ip char(15),
port int,
primary key(ip,port)
);
insert into t16 values
('1.1.1.2',80),
('1.1.1.2',81);
驗證複合主鍵的使用
5.auto_increment
約束:約束的字段爲自動增加,約束的字段必須同時被key約束
(重點)驗證:
# 建立student
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);
mysql> desc student;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | enum('male','female') | YES | | male | |
+-------+-----------------------+------+-----+---------+----------------+
rows in set (0.17 sec)
#插入記錄
mysql> insert into student(name) values ('老白'),('小白');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from student;
+----+--------+------+
| id | name | sex |
+----+--------+------+
| 1 | 老白 | male |
| 2 | 小白 | male |
+----+--------+------+
rows in set (0.00 sec)
不指定id,則自動增加
mysql> insert into student values(4,'asb','female');
Query OK, 1 row affected (0.00 sec)
mysql> insert into student values(7,'wsb','female');
Query OK, 1 row affected (0.01 sec)
mysql> select * from student;
+----+--------+--------+
| id | name | sex |
+----+--------+--------+
| 1 | 老白 | male |
| 2 | 小白 | male |
| 4 | asb | female |
| 7 | wsb | female |
+----+--------+--------+
rows in set (0.00 sec)
# 再次插入一條不指定id的記錄,會在以前的最後一條記錄繼續增加
mysql> insert into student(name) values ('大白');
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+--------+--------+
| id | name | sex |
+----+--------+--------+
| 1 | 老白 | male |
| 2 | 小白 | male |
| 4 | asb | female |
| 7 | wsb | female |
| 8 | 大白 | male |
+----+--------+--------+
rows in set (0.00 sec)
也能夠指定id
mysql> delete from student;
Query OK, 5 rows affected (0.00 sec)
mysql> select * from student;
Empty set (0.00 sec)
mysql> select * from student;
Empty set (0.00 sec)
mysql> insert into student(name) values('ysb');
Query OK, 1 row affected (0.01 sec)
mysql> select * from student;
+----+------+------+
| id | name | sex |
+----+------+------+
| 9 | ysb | male |
+----+------+------+
row in set (0.00 sec)
#應該用truncate清空表,比起delete一條一條地刪除記錄,truncate是直接清空表,在刪除大表時用它
mysql> truncate student;
Query OK, 0 rows affected (0.03 sec)
mysql> insert into student(name) values('xiaobai');
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+---------+------+
| id | name | sex |
+----+---------+------+
| 1 | xiaobai | male |
+----+---------+------+
row in set (0.00 sec)
mysql>
對於自增的字段,在用delete刪除後,再插入值,該字段仍按照刪除前的位置繼續增加
瞭解:
查看可用的 開頭auto_inc的詞
mysql> show variables like 'auto_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
+--------------------------+-------+
rows in set (0.02 sec)
# 步長auto_increment_increment,默認爲1
# 起始的偏移量auto_increment_offset, 默認是1
# 設置步長 爲會話設置,只在本次鏈接中有效
set session auto_increment_increment=5;
#全局設置步長 都有效。
set global auto_increment_increment=5;
# 設置起始偏移量
set global auto_increment_offset=3;
#強調:If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored.
翻譯:若是auto_increment_offset的值大於auto_increment_increment的值,則auto_increment_offset的值會被忽略
# 設置完起始偏移量和步長以後,再次執行show variables like'auto_inc%';
發現跟以前同樣,必須先exit,再登陸纔有效。
mysql> show variables like'auto_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 5 |
| auto_increment_offset | 3 |
+--------------------------+-------+
rows in set (0.00 sec)
#由於以前有一條記錄id=1
mysql> select * from student;
+----+---------+------+
| id | name | sex |
+----+---------+------+
| 1 | xiaobai | male |
+----+---------+------+
row in set (0.00 sec)
# 下次插入的時候,從起始位置3開始,每次插入記錄id+5
mysql> insert into student(name) values('ma1'),('ma2'),('ma3');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from student;
+----+---------+------+
| id | name | sex |
+----+---------+------+
| 1 | xiaobai | male |
| 3 | ma1 | male |
| 8 | ma2 | male |
| 13 | ma3 | male |
+----+---------+------+
auto_increment_increment和 auto_increment_offset
清空表區分delete和truncate的區別:
delete from t1; #若是有自增id,新增的數據,仍然是以刪除前的最後同樣做爲起始。
truncate table t1;數據量大,刪除速度比上一條快,且直接從零開始。
6.foreign key
一 快速理解foreign key
以前建立表的時候都是在一張表中添加記錄,好比以下表:
公司有3個部門,可是有1個億的員工,那意味着部門這個字段須要重複存儲,部門名字越長,越浪費。
這個時候,
解決方法:
咱們徹底能夠定義一個部門表
而後讓員工信息表關聯該表,如何關聯,即foreign key
咱們能夠將上表改成以下結構:
此時有兩張表,一張是employee表,簡稱emp表(關聯表,也就從表)。一張是department表,簡稱dep表(被關聯表,也叫主表)。
建立兩張表操做:
本節重點:
1、介紹
由於有foreign key的約束,使得兩張表造成了三種了關係:
2、重點理解若是找出兩張表之間的關係
分析步驟:
#一、先站在左表的角度去找
是否左表的多條記錄能夠對應右表的一條記錄,若是是,則證實左表的一個字段foreign key 右表一個字段(一般是id)
#二、再站在右表的角度去找
是否右表的多條記錄能夠對應左表的一條記錄,若是是,則證實右表的一個字段foreign key 左表一個字段(一般是id)
#三、總結:
#多對一:
若是隻有步驟1成立,則是左表多對一右表
若是隻有步驟2成立,則是右表多對一左表
#多對多
若是步驟1和2同時成立,則證實這兩張表時一個雙向的多對一,即多對多,須要定義一個這兩張表的關係表來專門存放兩者的關係
#一對一:
若是1和2都不成立,而是左表的一條記錄惟一對應右表的一條記錄,反之亦然。這種狀況很簡單,就是在左表foreign key右表的基礎上,將左表的外鍵字段設置成unique便可
3、表的三種關係
(1)書和出版社
一對多(或多對一):一個出版社能夠出版多本書。看圖說話。
關聯方式:foreign key
create table press(
id int primary key auto_increment,
name varchar(20)
);
create table book(
id int primary key auto_increment,
name varchar(20),
press_id int not null,
constraint fk_book_press foreign key(press_id) references press(id)
on delete cascade
on update cascade
);
# 先往被關聯表中插入記錄
insert into press(name) values
('北京工業地雷出版社'),
('人民音樂很差聽出版社'),
('知識產權沒有用出版社')
;
# 再往關聯表中插入記錄
insert into book(name,press_id) values
('九陽神功',1),
('九陰真經',2),
('九陰白骨爪',2),
('獨孤九劍',3),
('降龍十巴掌',2),
('葵花寶典',3)
;
查詢結果:
mysql> select * from book;
+----+-----------------+----------+
| id | name | press_id |
+----+-----------------+----------+
| 1 | 九陽神功 | 1 |
| 2 | 九陰真經 | 2 |
| 3 | 九陰白骨爪 | 2 |
| 4 | 獨孤九劍 | 3 |
| 5 | 降龍十巴掌 | 2 |
| 6 | 葵花寶典 | 3 |
+----+-----------------+----------+
rows in set (0.00 sec)
mysql> select * from press;
+----+--------------------------------+
| id | name |
+----+--------------------------------+
| 1 | 北京工業地雷出版社 |
| 2 | 人民音樂很差聽出版社 |
| 3 | 知識產權沒有用出版社 |
+----+--------------------------------+
rows in set (0.00 sec)
書和出版社(多對一)
(2)做者和書籍的關係
多對多:一個做者能夠寫多本書,一本書也能夠有多個做者,雙向的一對多,即多對多。
看圖說話。
關聯方式:foreign key+一張新的表
# 建立被關聯表author表,以前的book表在講多對一的關係已建立
create table author(
id int primary key auto_increment,
name varchar(20)
);
#這張表就存放了author表和book表的關係,即查詢兩者的關係查這表就能夠了
create table author2book(
id int not null unique auto_increment,
author_id int not null,
book_id int not null,
constraint fk_author foreign key(author_id) references author(id)
on delete cascade
on update cascade,
constraint fk_book foreign key(book_id) references book(id)
on delete cascade
on update cascade,
primary key(author_id,book_id)
);
#插入四個做者,id依次排開
insert into author(name) values('egon'),('alex'),('wusir'),('yuanhao');
# 每一個做者的表明做
egon: 九陽神功、九陰真經、九陰白骨爪、獨孤九劍、降龍十巴掌、葵花寶典
alex: 九陽神功、葵花寶典
wusir:獨孤九劍、降龍十巴掌、葵花寶典
yuanhao:九陽神功
# 在author2book表中插入相應的數據
insert into author2book(author_id,book_id) values
(1,1),
(1,2),
(1,3),
(1,4),
(1,5),
(1,6),
(2,1),
(2,6),
(3,4),
(3,5),
(3,6),
(4,1)
;
# 如今就能夠查author2book對應的做者和書的關係了
mysql> select * from author2book;
+----+-----------+---------+
| id | author_id | book_id |
+----+-----------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
| 5 | 1 | 5 |
| 6 | 1 | 6 |
| 7 | 2 | 1 |
| 8 | 2 | 6 |
| 9 | 3 | 4 |
| 10 | 3 | 5 |
| 11 | 3 | 6 |
| 12 | 4 | 1 |
+----+-----------+---------+
rows in set (0.00 sec)
做者與書籍關係(多對多)
(3)用戶和博客
一對一:一個用戶只能註冊一個博客,即一對一的關係。看圖說話
關聯方式:foreign key+unique
#例如: 一個用戶只能註冊一個博客
#兩張表: 用戶表 (user)和 博客表(blog)
# 建立用戶表
create table user(
id int primary key auto_increment,
name varchar(20)
);
# 建立博客表
create table blog(
id int primary key auto_increment,
url varchar(100),
user_id int unique,
constraint fk_user foreign key(user_id) references user(id)
on delete cascade
on update cascade
);
#插入用戶表中的記錄
insert into user(name) values
('alex'),
('wusir'),
('egon'),
('xiaoma')
;
# 插入博客表的記錄
insert into blog(url,user_id) values
('http://www.cnblog/alex',1),
('http://www.cnblog/wusir',2),
('http://www.cnblog/egon',3),
('http://www.cnblog/xiaoma',4)
;
# 查詢wusir的博客地址
select url from blog where user_id=2;
用戶和博客(一對一)
本節重點:
- 插入數據 INSERT
- 更新數據 UPDATE
- 刪除數據 DELETE
再來回顧一下以前咱們練過的一些操做,相信你們都對插入數據、更新數據、刪除數據有了全面的認識。那麼在mysql中其實最重要的不是這三大操做,而是查數據最重要,下節課知曉
1、
在MySQL管理軟件中,能夠經過SQL語句中的DML語言來實現數據的操做,包括
1.使用INSERT實現數據的插入
2.UPDATE實現數據的更新
3.使用DELETE實現數據的刪除
4.使用SELECT查詢數據以及。
2、插入數據 INSERT
1. 插入完整數據(順序插入)
語法一:
INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n);
語法二:
INSERT INTO 表名 VALUES (值1,值2,值3…值n);
2. 指定字段插入數據
語法:
INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…);
3. 插入多條記錄
語法:
INSERT INTO 表名 VALUES
(值1,值2,值3…值n),
(值1,值2,值3…值n),
(值1,值2,值3…值n);
4. 插入查詢結果
語法:
INSERT INTO 表名(字段1,字段2,字段3…字段n)
SELECT (字段1,字段2,字段3…字段n) FROM 表2
WHERE …;
3、更新數據UPDATE
語法:
UPDATE 表名 SET
字段1=值1,
字段2=值2,
WHERE CONDITION;
示例:
UPDATE mysql.user SET password=password(‘123’)
where user=’root’ and host=’localhost’;
4、刪除數據DELETE
語法:
DELETE FROM 表名
WHERE CONITION;
示例:
DELETE FROM mysql.user
WHERE password=’’;
本節重點:
單表查詢
語法:
1、單表查詢的語法
SELECT 字段1,字段2... FROM 表名
WHERE 條件
GROUP BY field
HAVING 篩選
ORDER BY field
LIMIT 限制條數
2、關鍵字的執行優先級(重點)
重點中的重點:關鍵字的執行優先級
from
where
group by
having
select
distinct
order by
limit
1.找到表:from
2.拿着where指定的約束條件,去文件/表中取出一條條記錄
3.將取出的一條條記錄進行分組group by,若是沒有group by,則總體做爲一組
4.將分組的結果進行having過濾
5.執行select
6.去重
7.將結果按條件排序:order by
8.限制結果的顯示條數
建立公司員工表,表的字段和數據類型
company.employee
員工id id int
姓名 name varchar
性別 sex enum
年齡 age int
入職日期 hire_date date
崗位 post varchar
職位描述 post_comment varchar
薪水 salary double
辦公室 office int
部門編號 depart_id int
#建立表,設置字段的約束條件
create table employee(
id int primary key auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int,#一個部門一個屋
depart_id int
);
# 查看錶結構
mysql> desc employee;
+--------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| emp_name | varchar(20) | NO | | NULL | |
| sex | enum('male','female') | NO | | male | |
| age | int(3) unsigned | NO | | 28 | |
| hire_date | date | NO | | NULL | |
| post | varchar(50) | YES | | NULL | |
| post_comment | varchar(100) | YES | | NULL | |
| salart | double(15,2) | YES | | NULL | |
| office | int(11) | YES | | NULL | |
| depart_id | int(11) | YES | | NULL | |
+--------------+-----------------------+------+-----+---------+----------------+
rows in set (0.08 sec)
#插入記錄
#三個部門:教學,銷售,運營
insert into employee(name ,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩駐沙河辦事處外交大使',7300.33,401,1), #如下是教學部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('xiaomage','male',48,'20101111','teacher',10000,401,1),
('歪歪','female',48,'20150311','sale',3000.13,402,2),#如下是銷售部門
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),
('張野','male',28,'20160311','operation',10000.13,403,3), #如下是運營部門
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬銀','female',18,'20130311','operation',19000,403,3),
('程咬銅','male',18,'20150411','operation',18000,403,3),
('程咬鐵','female',18,'20140512','operation',17000,403,3)
;
建立員工表,並插入記錄
(1)where 約束
where子句中能夠使用
1.比較運算符:>、<、>=、<=、<>、!=
2.between 80 and 100 :值在80到100之間
3.in(80,90,100)值是10或20或30
4.like 'xiaomagepattern': pattern能夠是%或者_。%小時任意多字符,_表示一個字符
5.邏輯運算符:在多個條件直接能夠使用邏輯運算符 and or not
驗證結果:
#1 :單條件查詢
mysql> select id,emp_name from employee where id > 5;
+----+------------+
| id | emp_name |
+----+------------+
| 6 | jingliyang |
| 7 | jinxin |
| 8 | xiaomage |
| 9 | 歪歪 |
| 10 | 丫丫 |
| 11 | 丁丁 |
| 12 | 星星 |
| 13 | 格格 |
| 14 | 張野 |
| 15 | 程咬金 |
| 16 | 程咬銀 |
| 17 | 程咬銅 |
| 18 | 程咬鐵 |
#2 多條件查詢
mysql> select emp_name from employee where post='teacher' and salary>10000;
+----------+
| emp_name |
+----------+
| alex |
| jinxin |
+----------+
#3.關鍵字BETWEEN AND
SELECT name,salary FROM employee
WHERE salary BETWEEN 10000 AND 20000;
SELECT name,salary FROM employee
WHERE salary NOT BETWEEN 10000 AND 20000;
#注意''是空字符串,不是null
SELECT name,post_comment FROM employee WHERE post_comment='';
ps:
執行
update employee set post_comment='' where id=2;
再用上條查看,就會有結果了
#5:關鍵字IN集合查詢
mysql> SELECT name,salary FROM employee WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;
+------------+---------+
| name | salary |
+------------+---------+
| yuanhao | 3500.00 |
| jingliyang | 9000.00 |
+------------+---------+
rows in set (0.00 sec)
mysql> SELECT name,salary FROM employee WHERE salary IN (3000,3500,4000,9000) ;
+------------+---------+
| name | salary |
+------------+---------+
| yuanhao | 3500.00 |
| jingliyang | 9000.00 |
+------------+---------+
mysql> SELECT name,salary FROM employee WHERE salary NOT IN (3000,3500,4000,9000) ;
+-----------+------------+
| name | salary |
+-----------+------------+
| egon | 7300.33 |
| alex | 1000000.31 |
| wupeiqi | 8300.00 |
| liwenzhou | 2100.00 |
| jinxin | 30000.00 |
| xiaomage | 10000.00 |
| 歪歪 | 3000.13 |
| 丫丫 | 2000.35 |
| 丁丁 | 1000.37 |
| 星星 | 3000.29 |
| 格格 | 4000.33 |
| 張野 | 10000.13 |
| 程咬金 | 20000.00 |
| 程咬銀 | 19000.00 |
| 程咬銅 | 18000.00 |
| 程咬鐵 | 17000.00 |
+-----------+------------+
rows in set (0.00 sec)
#6:關鍵字LIKE模糊查詢
通配符’%’
mysql> SELECT * FROM employee WHERE name LIKE 'jin%';
+----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+
| 6 | jingliyang | female | 18 | 2011-02-11 | teacher | NULL | 9000.00 | 401 | 1 |
| 7 | jinxin | male | 18 | 1900-03-01 | teacher | NULL | 30000.00 | 401 | 1 |
+----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+
rows in set (0.00 sec)
通配符'_'
mysql> SELECT age FROM employee WHERE name LIKE 'ale_';
+-----+
| age |
+-----+
| 78 |
+-----+
row in set (0.00 sec)
練習:
1. 查看崗位是teacher的員工姓名、年齡
2. 查看崗位是teacher且年齡大於30歲的員工姓名、年齡
3. 查看崗位是teacher且薪資在9000-1000範圍內的員工姓名、年齡、薪資
4. 查看崗位描述不爲NULL的員工信息
5. 查看崗位是teacher且薪資是10000或9000或30000的員工姓名、年齡、薪資
6. 查看崗位是teacher且薪資不是10000或9000或30000的員工姓名、年齡、薪資
7. 查看崗位是teacher且名字是jin開頭的員工姓名、年薪
#對應的sql語句
select name,age from employee where post = 'teacher';
select name,age from employee where post='teacher' and age > 30;
select name,age,salary from employee where post='teacher' and salary between 9000 and 10000;
select * from employee where post_comment is not null;
select name,age,salary from employee where post='teacher' and salary in (10000,9000,30000);
select name,age,salary from employee where post='teacher' and salary not in (10000,9000,30000);
select name,salary*12 from employee where post='teacher' and name like 'jin%';
where約束
(2)group by 分組查詢
#一、首先明確一點:分組發生在where以後,即分組是基於where以後獲得的記錄而進行的
#二、分組指的是:將全部記錄按照某個相同字段進行歸類,好比針對員工信息表的職位分組,或者按照性別進行分組等
#三、爲什麼要分組呢?
取每一個部門的最高工資
取每一個部門的員工數
取男人數和女人數
小竅門:‘每’這個字後面的字段,就是咱們分組的依據
#四、大前提:
能夠按照任意字段分組,可是分組完畢後,好比group by post,只能查看post字段,若是想查看組內信息,須要藉助於聚合函數
當執行如下sql語句的時候,是以post字段查詢了組中的第一條數據,沒有任何意義,由於咱們如今想查出當前組的多條記錄。
mysql> select * from employee group by post;
+----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
| 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 |
| 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 |
| 2 | alex | male | 78 | 2015-03-02 | teacher | | 1000000.31 | 401 | 1 |
| 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 |
+----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
4 rows in set (0.00 sec)
#因爲沒有設置ONLY_FULL_GROUP_BY,因而也能夠有結果,默認都是組內的第一條記錄,但其實這是沒有意義的
若是想分組,則必需要設置全局的sql的模式爲ONLY_FULL_GROUP_BY
mysql> set global sql_mode='ONLY_FULL_GROUP_BY';
Query OK, 0 rows affected (0.00 sec)
#查看MySQL 5.7默認的sql_mode以下:
mysql> select @@global.sql_mode;
+--------------------+
| @@global.sql_mode |
+--------------------+
| ONLY_FULL_GROUP_BY |
+--------------------+
1 row in set (0.00 sec)
mysql> exit;#設置成功後,必定要退出,而後從新登陸方可生效
Bye
繼續驗證經過group by分組以後,只能查看當前字段,若是想查看組內信息,須要藉助於聚合函數
mysql> select * from emp group by post;# 報錯
ERROR 1054 (42S22): Unknown column 'post' in 'group statement'
mysql> select post from employee group by post;
+-----------------------------------------+
| post |
+-----------------------------------------+
| operation |
| sale |
| teacher |
| 老男孩駐沙河辦事處外交大使 |
+-----------------------------------------+
4 rows in set (0.00 sec)
(3)聚合函數
max()求最大值
min()求最小值
avg()求平均值
sum() 求和
count() 求總個數
#強調:聚合函數聚合的是組的內容,如果沒有分組,則默認一組
# 每一個部門有多少個員工
select post,count(id) from employee group by post;
# 每一個部門的最高薪水
select post,max(salary) from employee group by post;
# 每一個部門的最低薪水
select post,min(salary) from employee group by post;
# 每一個部門的平均薪水
select post,avg(salary) from employee group by post;
# 每一個部門的全部薪水
select post,sum(age) from employee group by post;
1. 查詢崗位名以及崗位包含的全部員工名字
2. 查詢崗位名以及各崗位內包含的員工個數
3. 查詢公司內男員工和女員工的個數
4. 查詢崗位名以及各崗位的平均薪資
5. 查詢崗位名以及各崗位的最高薪資
6. 查詢崗位名以及各崗位的最低薪資
7. 查詢男員工與男員工的平均薪資,女員工與女員工的平均薪資
小練習
(4)HAVING過濾
HAVING與WHERE不同的地方在於
#!!!執行優先級從高到低:where > group by > having
#1. Where 發生在分組group by以前,於是Where中能夠有任意字段,可是絕對不能使用聚合函數。
#2. Having發生在分組group by以後,於是Having中能夠使用分組的字段,沒法直接取到其餘字段,能夠使用聚合函數
驗證:
驗證:
mysql> select * from employee where salary>1000000;
+----+------+------+-----+------------+---------+--------------+------------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+------+------+-----+------------+---------+--------------+------------+--------+-----------+
| 2 | alex | male | 78 | 2015-03-02 | teacher | | 1000000.31 | 401 | 1 |
+----+------+------+-----+------------+---------+--------------+------------+--------+-----------+
row in set (0.00 sec)
mysql> select * from employee having salary>1000000;
ERROR 1463 (42000): Non-grouping field 'salary' is used in HAVING clause
# 必須使用group by才能使用group_concat()函數,將全部的name值鏈接
mysql> select post,group_concat(name) from emp group by post having salary > 10000; ##錯誤,分組後沒法直接取到salary字段
ERROR 1054 (42S22): Unknown column 'post' in 'field list'
小練習:
1. 查詢各崗位內包含的員工個數小於2的崗位名、崗位內包含員工名字、個數
2. 查詢各崗位平均薪資大於10000的崗位名、平均工資
3. 查詢各崗位平均薪資大於10000且小於20000的崗位名、平均工資
小練習答案:
# 題1:
mysql> select post,group_concat(name),count(id) from employee group by post;
+-----------------------------------------+-----------------------------------------------------------+-----------+
| post | group_concat(name) | count(id) |
+-----------------------------------------+-----------------------------------------------------------+-----------+
| operation | 程咬鐵,程咬銅,程咬銀,程咬金,張野 | 5 |
| sale | 格格,星星,丁丁,丫丫,歪歪 | 5 |
| teacher | xiaomage,jinxin,jingliyang,liwenzhou,yuanhao,wupeiqi,alex | 7 |
| 老男孩駐沙河辦事處外交大使 | egon | 1 |
+-----------------------------------------+-----------------------------------------------------------+-----------+
rows in set (0.00 sec)
mysql> select post,group_concat(name),count(id) from employee group by post having count(id)<2;
+-----------------------------------------+--------------------+-----------+
| post | group_concat(name) | count(id) |
+-----------------------------------------+--------------------+-----------+
| 老男孩駐沙河辦事處外交大使 | egon | 1 |
+-----------------------------------------+--------------------+-----------+
row in set (0.00 sec)
#題2:
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000;
+-----------+---------------+
| post | avg(salary) |
+-----------+---------------+
| operation | 16800.026000 |
| teacher | 151842.901429 |
+-----------+---------------+
rows in set (0.00 sec)
#題3:
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 and avg(salary) <20000;
+-----------+--------------+
| post | avg(salary) |
+-----------+--------------+
| operation | 16800.026000 |
+-----------+--------------+
row in set (0.00 sec)
(5)order by 查詢排序
按單列排序
SELECT * FROM employee ORDER BY age;
SELECT * FROM employee ORDER BY age ASC;
SELECT * FROM employee ORDER BY age DESC;
按多列排序:先按照age升序排序,若是年紀相同,則按照id降序
SELECT * from employee
ORDER BY age ASC,
id DESC;
驗證多列排序:
SELECT * from employee ORDER BY age ASC,id DESC;
mysql> SELECT * from employee ORDER BY age ASC,id DESC;
+----+------------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+------------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
| 18 | 程咬鐵 | female | 18 | 2014-05-12 | operation | NULL | 17000.00 | 403 | 3 |
| 17 | 程咬銅 | male | 18 | 2015-04-11 | operation | NULL | 18000.00 | 403 | 3 |
| 16 | 程咬銀 | female | 18 | 2013-03-11 | operation | NULL | 19000.00 | 403 | 3 |
| 15 | 程咬金 | male | 18 | 1997-03-12 | operation | NULL | 20000.00 | 403 | 3 |
| 12 | 星星 | female | 18 | 2016-05-13 | sale | NULL | 3000.29 | 402 | 2 |
| 11 | 丁丁 | female | 18 | 2011-03-12 | sale | NULL | 1000.37 | 402 | 2 |
| 7 | jinxin | male | 18 | 1900-03-01 | teacher | NULL | 30000.00 | 401 | 1 |
| 6 | jingliyang | female | 18 | 2011-02-11 | teacher | NULL | 9000.00 | 401 | 1 |
| 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 |
| 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 |
| 13 | 格格 | female | 28 | 2017-01-27 | sale | NULL | 4000.33 | 402 | 2 |
| 5 | liwenzhou | male | 28 | 2012-11-01 | teacher | NULL | 2100.00 | 401 | 1 |
| 10 | 丫丫 | female | 38 | 2010-11-01 | sale | NULL | 2000.35 | 402 | 2 |
| 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 |
| 8 | xiaomage | male | 48 | 2010-11-11 | teacher | NULL | 10000.00 | 401 | 1 |
| 4 | yuanhao | male | 73 | 2014-07-01 | teacher | NULL | 3500.00 | 401 | 1 |
| 2 | alex | male | 78 | 2015-03-02 | teacher | | 1000000.31 | 401 | 1 |
| 3 | wupeiqi | male | 81 | 2013-03-05 | teacher | NULL | 8300.00 | 401 | 1 |
+----+------------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
rows in set (0.01 sec)
mysql>
驗證多列排序
小練習:
1. 查詢全部員工信息,先按照age升序排序,若是age相同則按照hire_date降序排序
2. 查詢各崗位平均薪資大於10000的崗位名、平均工資,結果按平均薪資升序排列
3. 查詢各崗位平均薪資大於10000的崗位名、平均工資,結果按平均薪資降序排列
# 題目1
select * from employee ORDER BY age asc,hire_date desc;
# 題目2
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) asc;
+-----------+---------------+
| post | avg(salary) |
+-----------+---------------+
| operation | 16800.026000 |
| teacher | 151842.901429 |
+-----------+---------------+
rows in set (0.00 sec)
# 題目3
mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) desc;
+-----------+---------------+
| post | avg(salary) |
+-----------+---------------+
| teacher | 151842.901429 |
| operation | 16800.026000 |
+-----------+---------------+
rows in set (0.00 sec)
mysql>
小練習答案
(5)limit 限制查詢的記錄數:
示例:
SELECT * FROM employee ORDER BY salary DESC
LIMIT 3; #默認初始位置爲0
SELECT * FROM employee ORDER BY salary DESC
LIMIT 0,5; #從第0開始,即先查詢出第一條,而後包含這一條在內日後查5條
SELECT * FROM employee ORDER BY salary DESC
LIMIT 5,5; #從第5開始,即先查詢出第6條,而後包含這一條在內日後查5條
小練習:
分頁顯示,每頁5條
# 第1頁數據
mysql> select * from employee limit 0,5;
+----+-----------+------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+-----------+------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
| 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 |
| 2 | alex | male | 78 | 2015-03-02 | teacher | | 1000000.31 | 401 | 1 |
| 3 | wupeiqi | male | 81 | 2013-03-05 | teacher | NULL | 8300.00 | 401 | 1 |
| 4 | yuanhao | male | 73 | 2014-07-01 | teacher | NULL | 3500.00 | 401 | 1 |
| 5 | liwenzhou | male | 28 | 2012-11-01 | teacher | NULL | 2100.00 | 401 | 1 |
+----+-----------+------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+
rows in set (0.00 sec)
# 第2頁數據
mysql> select * from employee limit 5,5;
+----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+
| 6 | jingliyang | female | 18 | 2011-02-11 | teacher | NULL | 9000.00 | 401 | 1 |
| 7 | jinxin | male | 18 | 1900-03-01 | teacher | NULL | 30000.00 | 401 | 1 |
| 8 | xiaomage | male | 48 | 2010-11-11 | teacher | NULL | 10000.00 | 401 | 1 |
| 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 |
| 10 | 丫丫 | female | 38 | 2010-11-01 | sale | NULL | 2000.35 | 402 | 2 |
+----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+
rows in set (0.00 sec)
# 第3頁數據
mysql> select * from employee limit 10,5;
+----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+
| 11 | 丁丁 | female | 18 | 2011-03-12 | sale | NULL | 1000.37 | 402 | 2 |
| 12 | 星星 | female | 18 | 2016-05-13 | sale | NULL | 3000.29 | 402 | 2 |
| 13 | 格格 | female | 28 | 2017-01-27 | sale | NULL | 4000.33 | 402 | 2 |
| 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 |
| 15 | 程咬金 | male | 18 | 1997-03-12 | operation | NULL | 20000.00 | 403 | 3 |
+----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+
rows in set (0.00 sec)
小練習答案
本節重點:
準備工做:準備兩張表,部門表(department)、員工表(employee)
create table department(
id int,
name varchar(20)
);
create table employee(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);
#插入數據
insert into department values
(200,'技術'),
(201,'人力資源'),
(202,'銷售'),
(203,'運營');
insert into employee(name,sex,age,dep_id) values
('egon','male',18,200),
('alex','female',48,201),
('wupeiqi','male',38,201),
('yuanhao','female',28,202),
('nvshen','male',18,200),
('xiaomage','female',18,204)
;
# 查看錶結構和數據
mysql> desc department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.19 sec)
mysql> desc employee;
+--------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | enum('male','female') | NO | | male | |
| age | int(11) | YES | | NULL | |
| dep_id | int(11) | YES | | NULL | |
+--------+-----------------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
mysql> select * from department;
+------+--------------+
| id | name |
+------+--------------+
| 200 | 技術 |
| 201 | 人力資源 |
| 202 | 銷售 |
| 203 | 運營 |
+------+--------------+
4 rows in set (0.02 sec)
mysql> select * from employee;
+----+----------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+----------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | nvshen | male | 18 | 200 |
| 6 | xiaomage | female | 18 | 204 |
+----+----------+--------+------+--------+
6 rows in set (0.00 sec)
ps:觀察兩張表,發現department表中id=203部門在employee中沒有對應的員工,發現employee中id=6的員工在department表中沒有對應關係。
1、多表鏈接查詢
兩張表的準備工做已完成,好比如今我要查詢的員工信息以及該員工所在的部門。從該題中,咱們看出既要查員工又要查該員工的部門,確定要將兩張表進行鏈接查詢,多表鏈接查詢。
重點:外連接語法
語法:
SELECT 字段列表
FROM 表1 INNER|LEFT|RIGHT JOIN 表2
ON 表1.字段 = 表2.字段;
(1)先看第一種狀況交叉鏈接:不適用任何匹配條件。生成笛卡爾積(關於笛卡爾積的含義,你們百度自行補腦)。
mysql> select * from employee,department;
+----+----------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+----+----------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 1 | egon | male | 18 | 200 | 201 | 人力資源 |
| 1 | egon | male | 18 | 200 | 202 | 銷售 |
| 1 | egon | male | 18 | 200 | 203 | 運營 |
| 2 | alex | female | 48 | 201 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 2 | alex | female | 48 | 201 | 202 | 銷售 |
| 2 | alex | female | 48 | 201 | 203 | 運營 |
| 3 | wupeiqi | male | 38 | 201 | 200 | 技術 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 202 | 銷售 |
| 3 | wupeiqi | male | 38 | 201 | 203 | 運營 |
| 4 | yuanhao | female | 28 | 202 | 200 | 技術 |
| 4 | yuanhao | female | 28 | 202 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 4 | yuanhao | female | 28 | 202 | 203 | 運營 |
| 5 | nvshen | male | 18 | 200 | 200 | 技術 |
| 5 | nvshen | male | 18 | 200 | 201 | 人力資源 |
| 5 | nvshen | male | 18 | 200 | 202 | 銷售 |
| 5 | nvshen | male | 18 | 200 | 203 | 運營 |
| 6 | xiaomage | female | 18 | 204 | 200 | 技術 |
| 6 | xiaomage | female | 18 | 204 | 201 | 人力資源 |
| 6 | xiaomage | female | 18 | 204 | 202 | 銷售 |
| 6 | xiaomage | female | 18 | 204 | 203 | 運營 |
(2)內鏈接:只鏈接匹配的行
#找兩張表共有的部分,至關於利用條件從笛卡爾積結果中篩選出了匹配的結果
#department沒有204這個部門,於是employee表中關於204這條員工信息沒有匹配出來
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id;
+----+---------+------+--------+--------------+
| id | name | age | sex | name |
+----+---------+------+--------+--------------+
| 1 | egon | 18 | male | 技術 |
| 2 | alex | 48 | female | 人力資源 |
| 3 | wupeiqi | 38 | male | 人力資源 |
| 4 | yuanhao | 28 | female | 銷售 |
| 5 | nvshen | 18 | male | 技術 |
+----+---------+------+--------+--------------+
5 rows in set (0.00 sec)
#上述sql等同於
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;
(3)外連接之左鏈接:優先顯示左表所有記錄
#以左表爲準,即找出全部員工信息,固然包括沒有部門的員工
#本質就是:在內鏈接的基礎上增長左邊有,右邊沒有的結果
mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id;
+----+----------+--------------+
| id | name | depart_name |
+----+----------+--------------+
| 1 | egon | 技術 |
| 5 | nvshen | 技術 |
| 2 | alex | 人力資源 |
| 3 | wupeiqi | 人力資源 |
| 4 | yuanhao | 銷售 |
| 6 | xiaomage | NULL |
+----+----------+--------------+
6 rows in set (0.00 sec)
(4) 外連接之右鏈接:優先顯示右表所有記錄
#以右表爲準,即找出全部部門信息,包括沒有員工的部門
#本質就是:在內鏈接的基礎上增長右邊有,左邊沒有的結果
mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id;
+------+---------+--------------+
| id | name | depart_name |
+------+---------+--------------+
| 1 | egon | 技術 |
| 2 | alex | 人力資源 |
| 3 | wupeiqi | 人力資源 |
| 4 | yuanhao | 銷售 |
| 5 | nvshen | 技術 |
| NULL | NULL | 運營 |
+------+---------+--------------+
6 rows in set (0.00 sec)
(5) 全外鏈接:顯示左右兩個表所有記錄(瞭解)
#外鏈接:在內鏈接的基礎上增長左邊有右邊沒有的和右邊有左邊沒有的結果
#注意:mysql不支持全外鏈接 full JOIN
#強調:mysql能夠使用此種方式間接實現全外鏈接
語法:select * from employee left join department on employee.dep_id = department.id
union all
select * from employee right join department on employee.dep_id = department.id;
mysql> select * from employee left join department on employee.dep_id = department.id
union
select * from employee right join department on employee.dep_id = department.id
;
+------+----------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+------+----------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技術 |
| 5 | nvshen | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 6 | xiaomage | female | 18 | 204 | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | 203 | 運營 |
+------+----------+--------+------+--------+------+--------------+
7 rows in set (0.01 sec)
#注意 union與union all的區別:union會去掉相同的紀錄
2、符合條件鏈接查詢
示例1:之內鏈接的方式查詢employee和department表,而且employee表中的age字段值必須大於25,即找出年齡大於25歲的員工以及員工所在的部門
select employee.name,department.name from employee inner join department
on employee.dep_id = department.id
where age > 25;
示例2:之內鏈接的方式查詢employee和department表,而且以age字段的升序方式顯示。
select employee.id,employee.name,employee.age,department.name from employee,department
where employee.dep_id = department.id
and age > 25
order by age asc;
3、子查詢
#1:子查詢是將一個查詢語句嵌套在另外一個查詢語句中。
#2:內層查詢語句的查詢結果,能夠爲外層查詢語句提供查詢條件。
#3:子查詢中能夠包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字
#4:還能夠包含比較運算符:= 、 !=、> 、<等
例子:
(1)帶in關鍵字的子查詢
#查詢平均年齡在25歲以上的部門名
select id,name from department
where id in
(select dep_id from employee group by dep_id having avg(age) > 25);
# 查看技術部員工姓名
select name from employee
where dep_id in
(select id from department where name='技術');
#查看不足1人的部門名
select name from department
where id not in
(select dep_id from employee group by dep_id);
(2)帶比較運算符的子查詢
#比較運算符:=、!=、>、>=、<、<=、<>
#查詢大於全部人平均年齡的員工名與年齡
mysql> select name,age from employee where age > (select avg(age) from employee);
+---------+------+
| name | age |
+---------+------+
| alex | 48 |
| wupeiqi | 38 |
+---------+------+
#查詢大於部門內平均年齡的員工名、年齡
思路:
(1)先對員工表(employee)中的人員分組(group by),查詢出dep_id以及平均年齡。
(2)將查出的結果做爲臨時表,再對根據臨時表的dep_id和employee的dep_id做爲篩選條件將employee表和臨時表進行內鏈接。
(3)最後再將employee員工的年齡是大於平均年齡的員工名字和年齡篩選。
mysql> select t1.name,t1.age from employee as t1
inner join
(select dep_id,avg(age) as avg_age from employee group by dep_id) as t2
on t1.dep_id = t2.dep_id
where t1.age > t2.avg_age;
+------+------+
| name | age |
+------+------+
| alex | 48 |
(3)帶EXISTS關鍵字的子查詢
#EXISTS關字鍵字表示存在。在使用EXISTS關鍵字時,內層查詢語句不返回查詢的記錄。而是返回一個真假值。True或False
#當返回True時,外層查詢語句將進行查詢;當返回值爲False時,外層查詢語句不進行查詢
#department表中存在dept_id=203,Ture
mysql> select * from employee where exists (select id from department where id=200);
+----+----------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+----------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | nvshen | male | 18 | 200 |
| 6 | xiaomage | female | 18 | 204 |
+----+----------+--------+------+--------+
#department表中存在dept_id=205,False
mysql> select * from employee where exists (select id from department where id=204);
Empty set (0.00 sec)
小練習:
查詢每一個部門最新入職的那位員工
#建立表
create table employee(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一個部門一個屋子
depart_id int
);
#查看錶結構
mysql> desc employee;
+--------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| sex | enum('male','female') | NO | | male | |
| age | int(3) unsigned | NO | | 28 | |
| hire_date | date | NO | | NULL | |
| post | varchar(50) | YES | | NULL | |
| post_comment | varchar(100) | YES | | NULL | |
| salary | double(15,2) | YES | | NULL | |
| office | int(11) | YES | | NULL | |
| depart_id | int(11) | YES | | NULL | |
+--------------+-----------------------+------+-----+---------+----------------+
#插入記錄
#三個部門:教學,銷售,運營
insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩駐沙河辦事處外交大使',7300.33,401,1), #如下是教學部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龍','male',48,'20101111','teacher',10000,401,1),
('歪歪','female',48,'20150311','sale',3000.13,402,2),#如下是銷售部門
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),
('張野','male',28,'20160311','operation',10000.13,403,3), #如下是運營部門
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬銀','female',18,'20130311','operation',19000,403,3),
('程咬銅','male',18,'20150411','operation',18000,403,3),
('程咬鐵','female',18,'20140512','operation',17000,403,3)
;
select * from employee as t1
inner join
(select post,max(hire_date) as new_date from employee group by post) as t2
on t1.post=t2.post
where t1.hire_date=t2.new_date;
權限管理
咱們知道咱們的最高權限管理者是root用戶,它擁有着最高的權限操做。包括select、update、delete、update、grant等操做。那麼通常狀況在公司以後DBA工程師會建立一個用戶和密碼,讓你去鏈接數據庫的操做,並給當前的用戶設置某個操做的權限(或者全部權限)。那麼這時就須要咱們來簡單瞭解一下:
- 如何建立用戶和密碼
- 給當前的用戶受權
- 移除當前用戶的權限
若是你想建立一個新的用戶,則須要如下操做:
1.進入到mysql數據庫下
mysql> use mysql
Database changed
2.對新用戶增刪改
1.建立用戶:
# 指定ip:192.118.1.1的mjj用戶登陸
create user 'mjj'@'192.118.1.1' identified by '123';
# 指定ip:192.118.1.開頭的mjj用戶登陸
create user 'mjj'@'192.118.1.%' identified by '123';
# 指定任何ip的mjj用戶登陸
create user 'mjj'@'%' identified by '123';
2.刪除用戶
drop user '用戶名'@'IP地址';
3.修改用戶
rename user '用戶名'@'IP地址' to '新用戶名'@'IP地址';
4.修改密碼
set password for '用戶名'@'IP地址'=Password('新密碼');
3.對當前的用戶受權管理
#查看權限
show grants for '用戶'@'IP地址'
#受權 mjj用戶僅對db1.t1文件有查詢、插入和更新的操做
grant select ,insert,update on db1.t1 to "mjj"@'%';
# 表示有全部的權限,除了grant這個命令,這個命令是root纔有的。mjj用戶對db1下的t1文件有任意操做
grant all privileges on db1.t1 to "mjj"@'%';
#mjj用戶對db1數據庫中的文件執行任何操做
grant all privileges on db1.* to "mjj"@'%';
#mjj用戶對全部數據庫中文件有任何操做
grant all privileges on *.* to "mjj"@'%';
#取消權限
# 取消mjj用戶對db1的t1文件的任意操做
revoke all on db1.t1 from 'mjj'@"%";
# 取消來自遠程服務器的mjj用戶對數據庫db1的全部表的全部權限
revoke all on db1.* from 'mjj'@"%";
取消來自遠程服務器的mjj用戶全部數據庫的全部的表的權限
revoke all privileges on *.* from 'mjj'@'%';
ps:在公司中,通常狀況下是DBA工程師來作這些受權工做。給你一個用戶名和密碼,你來鏈接就能夠了。
4.MySql備份命令行操做
# 備份:數據表結構+數據
mysqdump -u root db1 > db1.sql -p
# 備份:數據表結構
mysqdump -u root -d db1 > db1.sql -p
#導入現有的數據到某個數據庫
#1.先建立一個新的數據庫
create database db10;
# 2.將已有的數據庫文件導入到db10數據庫中
mysqdump -u root -d db10 < db1.sql -p
本節重點:
# PS:在生產環境中操做MySQL數據庫仍是推薦使用命令行工具mysql,但在咱們本身開發測試時,能夠使用可視化工具Navicat,以圖形界面的形式操做MySQL數據庫
官網下載:https://www.navicat.com/en/products/navicat-for-mysql
網盤下載:https://pan.baidu.com/s/1bpo5mqj
須要掌握基本的操做
掌握:
#1. 測試+連接數據庫
#2. 新建庫
#3. 新建表,新增字段+類型+約束
#4. 設計表:外鍵
#5. 新建查詢
#6. 備份庫/表
#注意:
批量加註釋:ctrl+?鍵
批量去註釋:ctrl+shift+?鍵
本節重點:
- pymysql的下載和使用
- execute()之sql注入
- 增、刪、改:conn.commit()
- 查:fetchone、fetchmany、fetchall
1、pymysql的下載和使用
以前咱們都是經過MySQL自帶的命令行客戶端工具mysql來操做數據庫,那如何在python程序中操做數據庫呢?這就用到了pymysql模塊,該模塊本質就是一個套接字客戶端軟件,使用前須要事先安裝。
(1)pymysql模塊的下載
(2)pymysql的使用
數據庫和數據都已存在
# 實現:使用Python實現用戶登陸,若是用戶存在則登陸成功(假設該用戶已在數據庫中)
import pymysql
user = input('請輸入用戶名:')
pwd = input('請輸入密碼:')
# 1.鏈接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.建立遊標
cursor = conn.cursor()
#注意%s須要加引號
sql = "select * from userinfo where username='%s' and pwd='%s'" %(user, pwd)
print(sql)
# 3.執行sql語句
cursor.execute(sql)
result=cursor.execute(sql) #執行sql語句,返回sql查詢成功的記錄數目
print(result)
# 關閉鏈接,遊標和鏈接都要關閉
cursor.close()
conn.close()
if result:
print('登錄成功')
else:
print('登陸失敗')
2、execute()之sql注入
最後那一個空格,在一條sql語句中若是遇到select * from userinfo where username='mjj' -- asadasdas' and pwd='' 則--以後的條件被註釋掉了(注意--後面還有一個空格)
#一、sql注入之:用戶存在,繞過密碼
mjj' -- 任意字符
#二、sql注入之:用戶不存在,繞過用戶與密碼
xxx' or 1=1 -- 任意字符
解決方法:
# 原來是咱們對sql進行字符串拼接
# sql="select * from userinfo where name='%s' and password='%s'" %(username,pwd)
# print(sql)
# result=cursor.execute(sql)
#改寫爲(execute幫咱們作字符串拼接,咱們無需且必定不能再爲%s加引號了)
sql="select * from userinfo where name=%s and password=%s" #!!!注意%s須要去掉引號,由於pymysql會自動爲咱們加上
result=cursor.execute(sql,[user,pwd]) #pymysql模塊自動幫咱們解決sql注入的問題,只要咱們按照pymysql的規矩來。
3、增、刪、改:conn.commit()
commit()方法:在數據庫裏增、刪、改的時候,必需要進行提交,不然插入的數據不生效。
import pymysql
username = input('請輸入用戶名:')
pwd = input('請輸入密碼:')
# 1.鏈接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.建立遊標
cursor = conn.cursor()
# 操做
# 增
# sql = "insert into userinfo(username,pwd) values (%s,%s)"
# effect_row = cursor.execute(sql,(username,pwd))
#同時插入多條數據
#cursor.executemany(sql,[('李四','110'),('王五','119')])
# print(effect_row)#
# 改
# sql = "update userinfo set username = %s where id = 2"
# effect_row = cursor.execute(sql,username)
# print(effect_row)
# 刪
sql = "delete from userinfo where id = 2"
effect_row = cursor.execute(sql)
print(effect_row)
#必定記得commit
conn.commit()
# 4.關閉遊標
cursor.close()
# 5.關閉鏈接
conn.close()
4、查:fetchone、fetchmany、fetchall
fetchone():獲取下一行數據,第一次爲首行;
fetchall():獲取全部行數據源
fetchmany(4):獲取4行數據
查看一下表內容:
mysql> select * from userinfo;
+----+----------+-----+
| id | username | pwd |
+----+----------+-----+
| 1 | mjj | 123 |
| 3 | 張三 | 110 |
| 4 | 李四 | 119 |
+----+----------+-----+
3 rows in set (0.00 sec)
使用fetchone():
import pymysql
# 1.鏈接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.建立遊標
cursor = conn.cursor()
sql = 'select * from userinfo'
cursor.execute(sql)
# 查詢第一行的數據
row = cursor.fetchone()
print(row) # (1, 'mjj', '123')
# 查詢第二行數據
row = cursor.fetchone()
print(row) # (3, '張三', '110')
# 4.關閉遊標
cursor.close()
# 5.關閉鏈接
conn.close()
使用fetchall():
import pymysql
# 1.鏈接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.建立遊標
cursor = conn.cursor()
sql = 'select * from userinfo'
cursor.execute(sql)
# 獲取全部的數據
rows = cursor.fetchall()
print(rows)
# 4.關閉遊標
cursor.close()
# 5.關閉鏈接
conn.close()
#運行結果
((1, 'mjj', '123'), (3, '張三', '110'), (4, '李四', '119'))
默認狀況下,咱們獲取到的返回值是元組,只能看到每行的數據,殊不知道每一列表明的是什麼,這個時候能夠使用如下方式來返回字典,每一行的數據都會生成一個字典:
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) #在實例化的時候,將屬性cursor設置爲pymysql.cursors.DictCursor
在fetchone示例中,在獲取行數據的時候,能夠理解開始的時候,有一個行指針指着第一行的上方,獲取一行,它就向下移動一行,因此當行指針到最後一行的時候,就不能再獲取到行的內容,因此咱們能夠使用以下方法來移動行指針:
cursor.scroll(1,mode='relative') # 相對當前位置移動
cursor.scroll(2,mode='absolute') # 相對絕對位置移動
第一個值爲移動的行數,整數爲向下移動,負數爲向上移動,mode指定了是相對當前位置移動,仍是相對於首行移動
# 1.Python實現用戶登陸
# 2.Mysql保存數據
import pymysql
# 1.鏈接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.建立遊標
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from userinfo'
cursor.execute(sql)
# 查詢第一行的數據
row = cursor.fetchone()
print(row) # (1, 'mjj', '123')
# 查詢第二行數據
row = cursor.fetchone() # (3, '張三', '110')
print(row)
cursor.scroll(-1,mode='relative') #設置以後,光標相對於當前位置往前移動了一行,因此打印的結果爲第二行的數據
row = cursor.fetchone()
print(row)
cursor.scroll(0,mode='absolute') #設置以後,光標相對於首行沒有任何變化,因此打印的結果爲第一行數據
row = cursor.fetchone()
print(row)
# 4.關閉遊標
cursor.close()
# 5.關閉鏈接
conn.close()
#結果以下
{'id': 1, 'username': 'mjj', 'pwd': '123'}
{'id': 3, 'username': '張三', 'pwd': '110'}
{'id': 3, 'username': '張三', 'pwd': '110'}
{'id': 1, 'username': 'mjj', 'pwd': '123'}
fetchmany():
import pymysql
# 1.鏈接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.建立遊標
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from userinfo'
cursor.execute(sql)
# 獲取2條數據
rows = cursor.fetchmany(2)
print(rows)
# 4.關閉遊標
# rows = cursor.fetchall()
# print(rows)
cursor.close()
# 5.關閉鏈接
conn.close()
#結果以下:
[{'id': 1, 'username': 'mjj', 'pwd': '123'}, {'id': 3, 'username': '張三', 'pwd': '110'}]
1、視圖的定義
視圖是虛擬表或邏輯表,它被定義爲具備鏈接的SQL SELECT查詢語句。由於數據庫視圖與數據庫表相似,它由行和列組成,所以能夠根據數據庫表查詢數據。其內容由查詢定義。
可是,視圖並不在數據庫中以存儲的數據值集形式存在,行和列數據來自由定義視圖的查詢所引用的表,而且在引用視圖時動態生成。簡單的來講視圖是由其定義結果組成的表;
2、視圖的優勢
一、數據庫視圖容許簡化複雜查詢,經過數據庫視圖,您只需使用簡單的SQL語句,而不是使用具備多個鏈接的複雜的SQL語句。
二、安全性。通常是這樣作的:建立一個視圖,定義好該視圖所操做的數據。以後將用戶權限與視圖綁定。這樣的方式是使用到了一個特性:grant語句能夠針對視圖進行授予權限。
3、視圖的缺點
一、性能:從數據庫視圖查詢數據可能會很慢,特別是若是視圖是基於其餘視圖建立的。
二、表依賴關係:將根據數據庫的基礎表建立一個視圖。每當更改與其相關聯的表的結構時,都必須更改視圖。
4、建立視圖
語法:
CREATE VIEW 視圖名稱 AS SQL語句
臨時表應用舉例:
#兩張有關係的表
mysql> select * from course;
+-----+--------+------------+
| cid | cname | teacher_id |
+-----+--------+------------+
| 1 | 生物 | 1 |
| 2 | 物理 | 2 |
| 3 | 體育 | 3 |
| 4 | 美術 | 2 |
+-----+--------+------------+
rows in set (0.00 sec)
mysql> select * from teacher;
+-----+-----------------+
| tid | tname |
+-----+-----------------+
| 1 | 張磊老師 |
| 2 | 李平老師 |
| 3 | 劉海燕老師 |
| 4 | 朱雲海老師 |
| 5 | 李傑老師 |
+-----+-----------------+
rows in set (0.00 sec)
#查詢李平老師教授的課程名
mysql> select cname from course where teacher_id = (select tid from teacher where tname='李平老師');
+--------+
| cname |
+--------+
| 物理 |
| 美術 |
+--------+
rows in set (0.00 sec)
#子查詢出臨時表,做爲teacher_id等判斷依據
select tid from teacher where tname='李平老師'
臨時表應用舉例
視圖的建立:
create view teacher_view as select tid from teacher where tname='李平老師';
#因而查詢李平老師教授的課程名的sql能夠改寫爲
mysql> select cname from course where teacher_id = (select tid from teacher_view);
+--------+
| cname |
+--------+
| 物理 |
| 美術 |
+--------+
rows in set (0.00 sec)
5、使用視圖
# 往真實表中插入一條數據,查看一下視圖,發現視圖表也會跟着更新
insert into course(cname,teacher_id) values('張三丰',2);
# 更新一下數據,發現視圖的數據也會跟着更新
update course set cname='王五';
不能修改視圖的數據,驗證爲例:
mysql> create view tt as select * from course left join teacher on teacher.tid = course.teacher_id;
Query OK, 0 rows affected (0.02 sec)
mysql> select * from tt;
+-----+--------+------------+------+-----------------+
| cid | cname | teacher_id | tid | tname |
+-----+--------+------------+------+-----------------+
| 1 | 王五 | 1 | 1 | 張磊老師 |
| 2 | 王五 | 2 | 2 | 麗萍老師 |
| 4 | 王五 | 2 | 2 | 麗萍老師 |
| 5 | 王五 | 2 | 2 | 麗萍老師 |
| 6 | 王五 | 2 | 2 | 麗萍老師 |
| 3 | 王五 | 3 | 3 | 王海燕老師 |
+-----+--------+------------+------+-----------------+
6 rows in set (0.01 sec)
mysql> insert into tt values(7,'哈哈',2,4,'張三丰老師');
ERROR 1471 (HY000): The target table tt of the INSERT is not insertable-into
6、修改視圖
# 語法:ALTER VIEW 視圖名稱 AS SQL語句
mysql> alter view teacher_view as select * from course where cid>3;
Query OK, 0 rows affected (0.04 sec)
mysql> select * from teacher_view;
+-----+-------+------------+
| cid | cname | teacher_id |
+-----+-------+------------+
| 4 | xxx | 2 |
| 5 | yyy | 2 |
+-----+-------+------------+
rows in set (0.00 sec)
7、刪除視圖
# 語法:DROP VIEW 視圖名稱
DROP VIEW teacher_view
使用觸發器能夠定製用戶對錶進行【增、刪、改】操做時先後的行爲,注意:沒有查詢
1、建立觸發器
# 插入前
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN
...
END
# 插入後
CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
BEGIN
...
END
# 刪除前
CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
BEGIN
...
END
# 刪除後
CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
BEGIN
...
END
# 更新前
CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
BEGIN
...
END
# 更新後
CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
BEGIN
...
END
例子:用戶和日誌表。每次建立一個用戶以後,就在日誌布表中生成這條記錄
準備表:
# 建立用戶表
create table user(
id int primary key auto_increment,
name varchar(20) not null,
reg_time datetime, # 註冊用戶的時間
affirm enum('yes','no') # no表示該用戶執行失敗
);
#建立日誌表
create table userLog(
id int primary key auto_increment,
u_name varchar(20) not null,
u_reg_time datetime # 註冊用戶的時間
);
# 建立觸發器 delimiter 默認狀況下,delimiter是分號 觸發器名稱應遵循命名約定
delimiter //
create trigger after_user_insert after insert on user for each row
begin
if new.affirm = 'yes' then
insert into userLog(u_name,u_reg_time) values(new.name,new.reg_time);
end if;
end //
delimiter ;
#往用戶表中插入記錄,觸發觸發器,根據if的條件決定是否插入數據
insert into user(name,reg_time,affirm) values ('張三',now(),'yes'),('李四',now(),'yes'),('王五',now(),'no');
# 查看日誌表,發現多了兩條記錄 ,你們應該看到for each row就明白了
mysql> select * from userlog;
+----+--------+---------------------+
| id | u_name | u_reg_time |
+----+--------+---------------------+
| 1 | 張三 | 2018-06-14 17:52:49 |
| 2 | 李四 | 2018-06-14 17:52:49 |
+----+--------+---------------------+
2 rows in set (0.00 sec)[trigger time]_[table name]_[trigger event]
注意:請注意,在爲INSERT定義的觸發器中,能夠僅使用NEW
關鍵字。不能使用OLD
關鍵字。可是,在爲DELETE
定義的觸發器中,沒有新行,所以您只能使用OLD
關鍵字。在UPDATE觸發器中,OLD
是指更新前的行,而NEW
是更新後的行
二 使用觸發器
觸發器沒法由用戶直接調用,而知因爲對錶的【增/刪/改】操做被動引起的。
三 刪除觸發器
drop trigger trigger_userLog;
1、數學函數
ROUND(x,y)
返回參數x的四捨五入的有y位小數的值
RAND()
返回0到1內的隨機值,能夠經過提供一個參數(種子)使RAND()隨機數生成器生成一個指定的值。
2、聚合函數(經常使用於GROUP BY從句的SELECT查詢中)
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的個數
MIN(col)返回指定列的最小值
MAX(col)返回指定列的最大值
SUM(col)返回指定列的全部值之和
GROUP_CONCAT(col) 返回由屬於一組的列值鏈接組合而成的結果
3、字符串函數
CHAR_LENGTH(str)
返回值爲字符串str 的長度,長度的單位爲字符。一個多字節字符算做一個單字符。
CONCAT(str1,str2,...)
字符串拼接
若有任何一個參數爲NULL ,則返回值爲 NULL。
CONCAT_WS(separator,str1,str2,...)
字符串拼接(自定義鏈接符)
CONCAT_WS()不會忽略任何空字符串。 (然而會忽略全部的 NULL)。
CONV(N,from_base,to_base)
進制轉換
例如:
SELECT CONV('a',16,2); 表示將 a 由16進制轉換爲2進制字符串表示
FORMAT(X,D)
將數字X 的格式寫爲'#,###,###.##',以四捨五入的方式保留小數點後 D 位, 並將結果以字符串的形式返回。若 D 爲 0, 則返回結果不帶有小數點,或不含小數部分。
例如:
SELECT FORMAT(12332.1,4); 結果爲: '12,332.1000'
INSERT(str,pos,len,newstr)
在str的指定位置插入字符串
pos:要替換位置其實位置
len:替換的長度
newstr:新字符串
特別的:
若是pos超過原字符串長度,則返回原字符串
若是len超過原字符串長度,則由新字符串徹底替換
INSTR(str,substr)
返回字符串 str 中子字符串的第一個出現位置。
LEFT(str,len)
返回字符串str 從開始的len位置的子序列字符。
LOWER(str)
變小寫
UPPER(str)
變大寫
REVERSE(str)
返回字符串 str ,順序和字符順序相反。
SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
不帶有len 參數的格式從字符串str返回一個子字符串,起始於位置 pos。帶有len參數的格式從字符串str返回一個長度同len字符相同的子字符串,起始於位置 pos。 使用 FROM的格式爲標準 SQL 語法。也可能對pos使用一個負值。倘若這樣,則子字符串的位置起始於字符串結尾的pos 字符,而不是字符串的開頭位置。在如下格式的函數中能夠對pos 使用一個負值。
mysql> SELECT SUBSTRING('Quadratically',5);
-> 'ratically'
mysql> SELECT SUBSTRING('foobarbar' FROM 4);
-> 'barbar'
mysql> SELECT SUBSTRING('Quadratically',5,6);
-> 'ratica'
mysql> SELECT SUBSTRING('Sakila', -3);
-> 'ila'
mysql> SELECT SUBSTRING('Sakila', -5, 3);
-> 'aki'
mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
-> 'ki'
4、日期和時間函數
CURDATE()或CURRENT_DATE() 返回當前的日期
CURTIME()或CURRENT_TIME() 返回當前的時間
DAYOFWEEK(date) 返回date所表明的一星期中的第幾天(1~7)
DAYOFMONTH(date) 返回date是一個月的第幾天(1~31)
DAYOFYEAR(date) 返回date是一年的第幾天(1~366)
DAYNAME(date) 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt) 根據指定的fmt格式,格式化UNIX時間戳ts
HOUR(time) 返回time的小時值(0~23)
MINUTE(time) 返回time的分鐘值(0~59)
MONTH(date) 返回date的月份值(1~12)
MONTHNAME(date) 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW() 返回當前的日期和時間
QUARTER(date) 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
WEEK(date) 返回日期date爲一年中第幾周(0~53)
YEAR(date) 返回日期date的年份(1000~9999)
重點:
DATE_FORMAT(date,format) 根據format字符串格式化date值
mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
-> 'Sunday October 2009'
mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
-> '22:23:00'
mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
-> '%D %y %a %d %m %b %j');
-> '4th 00 Thu 04 10 Oct 277'
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
-> '%H %k %I %r %T %S %w');
-> '22 22 10 10:23:00 PM 22:23:00 00 6'
mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
-> '1998 52'
mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
-> '00'
5、加密函數
MD5()
計算字符串str的MD5校驗和
PASSWORD(str)
返回字符串str的加密版本,這個加密過程是不可逆轉的,和UNIX密碼加密過程使用不一樣的算法。
6、控制流函數
CASE WHEN[test1] THEN [result1]...ELSE [default] END
若是testN是真,則返回resultN,不然返回default
CASE [test] WHEN[val1] THEN [result]...ELSE [default]END
若是test和valN相等,則返回resultN,不然返回default
IF(test,t,f)
若是test是真,返回t;不然返回f
IFNULL(arg1,arg2)
若是arg1不是空,返回arg1,不然返回arg2
NULLIF(arg1,arg2)
若是arg1=arg2返回NULL;不然返回arg1
內置函數
更多函數:中文猛擊這裏 OR 官方猛擊這裏
掌握內置函數中的時間格式化DATE_FORMAT()的用法
官網示例:
mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
-> 'Sunday October 2009'
mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
-> '22:23:00'
mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
-> '%D %y %a %d %m %b %j');
-> '4th 00 Thu 04 10 Oct 277'
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
-> '%H %k %I %r %T %S %w');
-> '22 22 10 10:23:00 PM 22:23:00 00 6'
mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
-> '1998 52'
mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
-> '00'
舉例:
# 一、博客園 時間處理
CREATE TABLE blog (
id INT PRIMARY KEY auto_increment,
NAME CHAR (32),
sub_time datetime
);
#二、插入數據
INSERT INTO blog (NAME, sub_time)
VALUES
('第1篇','2015-03-01 11:31:21'),
('第2篇','2015-03-11 16:31:21'),
('第3篇','2016-07-01 10:21:31'),
('第4篇','2016-07-22 09:23:21'),
('第5篇','2016-07-23 10:11:11'),
('第6篇','2016-07-25 11:21:31'),
('第7篇','2017-03-01 15:33:21'),
('第8篇','2017-03-01 17:32:21'),
('第9篇','2017-03-01 18:31:21');
#3. 提取sub_time字段的值,按照格式後的結果即"年月"來分組
SELECT DATE_FORMAT(sub_time,'%Y-%m') as y_m,COUNT(1) as num FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y-%m');
# 結果:
+---------+-----+
| y_m | num |
+---------+-----+
| 2015-03 | 2 |
| 2016-07 | 4 |
| 2017-03 | 3 |
+---------+-----+
3 rows in set (0.00 sec)
1、存儲過程的定義
存儲過程是存儲在數據庫目錄中的一坨的聲明性SQL語句。
Java,Python,PHP等應用程序能夠調用存儲過程。
MySQL是最受歡迎的開源RDBMS,被社區和企業普遍使用。 然而,在它發佈的第一個十年期間,它不支持存儲過程,存儲函數,觸發器和事件。自從MySQL 5.0版本以來,這些功能被添加到MySQL數據庫引擎,使其更加靈活和強大。
2、存儲過程的優勢
#一、一般存儲過程有助於提升應用程序的性能。當建立,存儲過程被編譯以後,就存儲在數據庫中。 可是,MySQL實現的存儲過程略有不一樣。 MySQL存儲過程按需編譯。 在編譯存儲過程以後,MySQL將其放入緩存中。 MySQL爲每一個鏈接維護本身的存儲過程高速緩存。 若是應用程序在單個鏈接中屢次使用存儲過程,則使用編譯版本,不然存儲過程的工做方式相似於查詢。
# 二、存儲過程有助於減小應用程序和數據庫服務器之間的流量,由於應用程序沒必要發送多個冗長的SQL語句,而只能發送存儲過程的名稱和參數。
#三、存儲的程序對任何應用程序都是可重用的和透明的。 存儲過程將數據庫接口暴露給全部應用程序,以便開發人員沒必要開發存儲過程當中已支持的功能。
#四、存儲的程序是安全的。 數據庫管理員能夠向訪問數據庫中存儲過程的應用程序授予適當的權限,而不向基礎數據庫表提供任何權限。
除了這些優勢以外,存儲過程有其自身的缺點,在數據庫中使用它們以前,您應該注意這些缺點。
3、存儲過程的缺點
#一、若是使用大量存儲過程,那麼使用這些存儲過程的每一個鏈接的內存使用量將會大大增長。 此外,若是您在存儲過程當中過分使用大量邏輯操做,則CPU使用率也會增長,由於數據庫服務器的設計不當於邏輯運算。
#二、存儲過程的構造使得開發具備複雜業務邏輯的存儲過程變得更加困難。
#三、很難調試存儲過程。只有少數數據庫管理系統容許您調試存儲過程。不幸的是,MySQL不提供調試存儲過程的功能。
#四、開發和維護存儲過程並不容易。開發和維護存儲過程一般須要一個不是全部應用程序開發人員擁有的專業技能。這可能會致使應用程序開發和維護階段的問題。
MySQL存儲過程有本身的優勢和缺點。開發應用程序時,您應該決定是否應該或不該該根據業務需求使用存儲過程。
4、一個簡單的Mysql存儲過程示例
delimiter //
create procedure b1()
begin
select * from blog;
end //
delimiter ;
解釋:
1.第一個命令是delimiter //,它與存儲過程語法無關。 delimter語句將標準分隔符 - 分號(;)更改成://。 在這種狀況下,分隔符從分號(;)更改成雙斜槓//。爲何咱們必須更改分隔符? 由於咱們想將存儲過程做爲總體傳遞給服務器,而不是讓mysql工具一次解釋每一個語句。 在END關鍵字以後,使用分隔符//來指示存儲過程的結束。 最後一個命令(DELIMITER;)將分隔符更改回分號(;)。
2.使用create procedure語句建立一個新的存儲過程。在create procedure語句以後指定存儲過程的名稱。在這個示例中,存儲過程的名稱爲:b1,並把括號放在存儲過程的名字以後。
3.begin和end之間的部分稱爲存儲過程的主體。將聲明性SQL語句放在主體中以處理業務邏輯。 在這個存儲過程當中,咱們使用一個簡單的select語句來查詢blog表中的數據。
# mysql中調用存儲過程
call b1()
#在python中基於pymysql調用
cursor.callproc('b1')
print(cursor.fetchall())
5、聲明變量
要在存儲過程當中聲明變量,能夠使用delclare語句,以下
DECLARE variable_name datatype(size) DEFAULT default_value;
下面來更詳細地解釋上面的語句:
首先,在DECLARE關鍵字後面要指定變量名。變量名必須遵循MySQL表列名稱的命名規則。
其次,指定變量的數據類型及其大小。變量能夠有任何MySQL數據類型,如INT,VARCHAR,DATETIME等。
第三,當聲明一個變量時,它的初始值爲NULL。可是能夠使用DEFAULT關鍵字爲變量分配默認值。
實現:
delimiter //
create procedure b2()
begin
DECLARE n int DEFAULT 1;
set n = 5;
select * from blog where id = n;
end //
delimiter ;
# mysql中調用存儲過程
call b2();
6、存儲過程傳參
在現實應用中,開發的存儲過程幾乎都須要參數。這些參數使存儲過程更加靈活和有用。 在MySQL中,參數有三種模式:IN,OUT或INOUT。
IN - 是默認模式。在存儲過程當中定義IN參數時,調用程序必須將參數傳遞給存儲過程。 另外,IN參數的值被保護。這意味着即便在存儲過程當中更改了IN參數的值,在存儲過程結束後仍保留其原始值。換句話說,存儲過程只使用IN參數的副本。
OUT - 能夠在存儲過程當中更改OUT參數的值,並將其更改後新值傳遞迴調用程序。請注意,存儲過程在啓動時沒法訪問OUT參數的初始值。
INOUT - INOUT參數是IN和OUT參數的組合。這意味着調用程序能夠傳遞參數,而且存儲過程能夠修改INOUT參數並將新值傳遞迴調用程序。
在存儲過程當中定義參數的語法以下:
MODE param_name param_type(param_size)
根據存儲過程當中參數的目的,MODE能夠是IN,OUT或INOUT。
param_name是參數的名稱。參數的名稱必須遵循MySQL中列名的命名規則。
在參數名以後是它的數據類型和大小。和變量同樣,參數的數據類型能夠是任何有效的MySQL數據類型
ps:若是存儲過程有多個參數,則每一個參數由逗號(,)分隔。
# 1.in
delimiter //
create procedure b3(
in blogName varchar(30)
)
begin
select * from blog where NAME = blogName;
end //
delimiter ;
#mysql中調用存儲過程
call b3('第5篇');
#python中調用存儲過程
cursor.callproc('b3',args = ('第5篇'));
# 2.out
delimiter //
create procedure b4(
in year int,
out count int
)
begin
SELECT COUNT(1) into count FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y') having max(DATE_FORMAT(sub_time,'%Y')) = year ;
set count = 6;
end //
delimiter ;
call b4(2016,@count);
select @count;
#out只能當返回值
# 3.inout
delimiter //
create procedure b5(
inout n1 int
)
begin
select * from blog where id > n1;
end //
delimiter ;
#mysql中調用
set @n = 3;
call b5(@n);
select @n;
#在python中基於pymysql調用
cursor.callproc('b5',(4))
print(cursor.fetchall()) #查詢select的查詢結果
cursor.execute('select @n1')
print(cursor.fetchall())
# inout:既能夠傳入又能夠返回
事務用於將某些操做的多個SQL做爲原子性操做,一旦有某一個出現錯誤,便可回滾到原來的狀態,從而保證數據庫數據完整性。
舉例說明:
create table user2(
id int primary key auto_increment,
name char(32),
balance int
);
insert into user2(name,balance)
values
('wsb',1000),
('egon',1000),
('ysb',1000);
#原子操做
start transaction;
update user2 set balance=900 where name='wsb'; #買支付100元
update user2 set balance=1010 where name='egon'; #中介拿走10元
update user2 set balance=1090 where name='ysb'; #賣家拿到90元
commit;
#出現異常,回滾到初始狀態
start transaction;
update user2 set balance=900 where name='wsb'; #買支付100元
update user2 set balance=1010 where name='egon'; #中介拿走10元
uppdate user2 set balance=1090 where name='ysb'; #賣家拿到90元,出現異常沒有拿到
rollback;
mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 1 | wsb | 1000 |
| 2 | egon | 1000 |
| 3 | ysb | 1000 |
+----+------+---------+
rows in set (0.00 sec)
下面是操做:當p_return_code爲1時,表示異常,立馬回滾。當爲2時,出現警告,立馬回滾原始狀態。0表示成功
delimiter //
create PROCEDURE b6(
OUT p_return_code tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
set p_return_code = 1;
rollback;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
set p_return_code = 2;
rollback;
END;
START TRANSACTION;
insert into blog(name,sub_time) values('yyy',now());
COMMIT;
-- SUCCESS
set p_return_code = 0; #0表明執行成功
END //
delimiter ;
set @res=123;
call b6(@res);
select @res;
1、索引的介紹
數據庫中專門用於幫助用戶快速查找數據的一種數據結構。相似於字典中的目錄,查找字典內容時能夠根據目錄查找到數據的存放位置嗎,而後直接獲取。
二 、索引的做用
3、常見的幾種索引:
- 普通索引
- 惟一索引
- 主鍵索引
- 聯合索引(多列)
- 聯合主鍵索引
- 聯合惟一索引
- 聯合普通索引
無索引: 從前日後一條一條查詢
有索引:建立索引的本質,就是建立額外的文件(某種格式存儲,查詢的時候,先去格外的文件找,定好位置,而後再去原始表中直接查詢。可是建立索引越多,會對硬盤也是有損耗。
創建索引的目的:
a.額外的文件保存特殊的數據結構
b.查詢快,可是插入更新刪除依然慢
c.建立索引以後,必須命中索引纔能有效
無索引和有索引的區別以及創建索引的目的
hash索引和BTree索引
(1)hash類型的索引:查詢單條快,範圍查詢慢
(2)btree類型的索引:b+樹,層數越多,數據量指數級增加(咱們就用它,由於innodb默認支持它)
3.1 普通索引
做用:僅有一個加速查找
create table userinfo(
nid int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
index ix_name(name)
);
建立表+普通索引
create index 索引的名字 on 表名(列名)
3.2 惟一索引
惟一索引有兩個功能:加速查找和惟一約束(可含null)
create table userinfo(
id int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
unique index ix_name(name)
);
建立表+惟一索引
create unique index 索引名 on 表名(列名)
3.3 主鍵索引
主鍵索引有兩個功能: 加速查找和惟一約束(不含null)
create table userinfo(
id int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
unique index ix_name(name)
)
or
create table userinfo(
id int not null auto_increment,
name varchar(32) not null,
email varchar(64) not null,
primary key(nid),
unique index ix_name(name)
)
建立表+主鍵索引
alter table 表名 add primary key(列名);
alter table 表名 drop primary key;
alter table 表名 modify 列名 int, drop primary key;
3.4 組合索引
組合索引是將n個列組合成一個索引
其應用場景爲:頻繁的同時使用n列來進行查詢,如:where name = 'alex' and email = 'alex@qq.com'。
create index 索引名 on 表名(列名1,列名2);
4、索引名詞
#覆蓋索引:在索引文件中直接獲取數據
例如:
select name from userinfo where name = 'alex50000';
#索引合併:把多個單列索引合併成使用
例如:
select * from userinfo where name = 'alex13131' and id = 13131;
6、正確使用索引的狀況
數據庫表中添加索引後確實會讓查詢速度起飛,但前提必須是正確的使用索引來查詢,若是以錯誤的方式使用,則即便創建索引也會不奏效。
使用索引,咱們必須知道:
(1)建立索引
(2)命中索引
(3)正確使用索引
準備:
#1. 準備表
create table userinfo(
id int,
name varchar(20),
gender char(6),
email varchar(50)
);
#2. 建立存儲過程,實現批量插入記錄
delimiter $$ #聲明存儲過程的結束符號爲$$
create procedure auto_insert1()
BEGIN
declare i int default 1;
while(i<3000000)do
insert into userinfo values(i,concat('alex',i),'male',concat('egon',i,'@oldboy'));
set i=i+1;
end while;
END$$ #$$結束
delimiter ; #從新聲明分號爲結束符號
#3. 查看存儲過程
show create procedure auto_insert1\G
#4. 調用存儲過程
call auto_insert1();
準備300w條數據
測試:
- like '%xx'
select * from userinfo where name like '%al';
- 使用函數
select * from userinfo where reverse(name) = 'alex333';
- or
select * from userinfo where id = 1 or email = 'alex122@oldbody';
特別的:當or條件中有未創建索引的列才失效,如下會走索引
select * from userinfo where id = 1 or name = 'alex1222';
select * from userinfo where id = 1 or email = 'alex122@oldbody' and name = 'alex112'
- 類型不一致
若是列是字符串類型,傳入條件是必須用引號引發來,否則...
select * from userinfo where name = 999;
- !=
select count(*) from userinfo where name != 'alex'
特別的:若是是主鍵,則仍是會走索引
select count(*) from userinfo where id != 123
- >
select * from userinfo where name > 'alex'
特別的:若是是主鍵或索引是整數類型,則仍是會走索引
select * from userinfo where id > 123
select * from userinfo where num > 123
- order by
select email from userinfo order by name desc;
當根據索引排序時候,選擇的映射若是不是索引,則不走索引
特別的:若是對主鍵排序,則仍是走索引:
select * from userinfo order by nid desc;
- 組合索引最左前綴
若是組合索引爲:(name,email)
name and email -- 使用索引
name -- 使用索引
email -- 不使用索引
什麼是最左前綴呢?
最左前綴匹配:
create index ix_name_email on userinfo(name,email);
select * from userinfo where name = 'alex';
select * from userinfo where name = 'alex' and email='alex@oldBody';
select * from userinfo where email='alex@oldBody';
若是使用組合索引如上,name和email組合索引以後,查詢
(1)name和email ---使用索引
(2)name ---使用索引
(3)email ---不適用索引
對於同時搜索n個條件時,組合索引的性能好於多個單列索引
******組合索引的性能>索引合併的性能*********
7、索引的注意事項
(1)避免使用select *
(2)count(1)或count(列) 代替count(*)
(3)建立表時儘可能使用char代替varchar
(4)表的字段順序固定長度的字段優先
(5)組合索引代替多個單列索引(常用多個條件查詢時)
(6)儘可能使用短索引 (create index ix_title on tb(title(16));特殊的數據類型 text類型)
(7)使用鏈接(join)來代替子查詢
(8)連表時注意條件類型需一致
(9)索引散列(重複少)不適用於建索引,例如:性別不合適
8、執行計劃
explain + 查詢SQL - 用於顯示SQL執行信息參數,根據參考信息能夠進行SQL優化
mysql> explain select * from userinfo;
+----+-------------+----------+------+---------------+------+---------+------+---------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+---------+-------+
| 1 | SIMPLE | userinfo | ALL | NULL | NULL | NULL | NULL | 2973016 | NULL |
+----+-------------+----------+------+---------------+------+---------+------+---------+-------+
mysql> explain select * from (select id,name from userinfo where id <20) as A;
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 19 | NULL |
| 2 | DERIVED | userinfo | range | PRIMARY | PRIMARY | 4 | NULL | 19 | Using where |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
2 rows in set (0.05 sec)
參數說明:
select_type:
查詢類型
SIMPLE 簡單查詢
PRIMARY 最外層查詢
SUBQUERY 映射爲子查詢
DERIVED 子查詢
UNION 聯合
UNION RESULT 使用聯合的結果
table:
正在訪問的表名
type:
查詢時的訪問方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
ALL 全表掃描,對於數據表從頭至尾找一遍
select * from userinfo;
特別的:若是有limit限制,則找到以後就不在繼續向下掃描
select * from userinfo where email = 'alex112@oldboy'
select * from userinfo where email = 'alex112@oldboy' limit 1;
雖然上述兩個語句都會進行全表掃描,第二句使用了limit,則找到一個後就再也不繼續掃描。
INDEX : 全索引掃描,對索引從頭至尾找一遍
select nid from userinfo;
RANGE: 對索引列進行範圍查找
select * from userinfo where name < 'alex';
PS:
between and
in
> >= < <= 操做
注意:!= 和 > 符號
INDEX_MERGE: 合併索引,使用多個單列索引搜索
select * from userinfo where name = 'alex' or nid in (11,22,33);
REF: 根據索引查找一個或多個值
select * from userinfo where name = 'alex112';
EQ_REF: 鏈接時使用primary key 或 unique類型
select userinfo2.id,userinfo.name from userinfo2 left join tuserinfo on userinfo2.id = userinfo.id;
CONST:常量
表最多有一個匹配行,由於僅有一行,在這行的列值可被優化器剩餘部分認爲是常數,const表很快,由於它們只讀取一次。
select id from userinfo where id = 2 ;
SYSTEM:系統
表僅有一行(=系統表)。這是const聯接類型的一個特例。
select * from (select id from userinfo where id = 1) as A;
possible_keys:可能使用的索引
key:真實使用的
key_len: MySQL中使用索引字節長度
rows: mysql估計爲了找到所需的行而要讀取的行數 ------ 只是預估值
extra:
該列包含MySQL解決查詢的詳細信息
「Using index」
此值表示mysql將使用覆蓋索引,以免訪問表。不要把覆蓋索引和index訪問類型弄混了。
「Using where」
這意味着mysql服務器將在存儲引擎檢索行後再進行過濾,許多where條件裏涉及索引中的列,當(而且若是)它讀取索引時,就能被存儲引擎檢驗,所以不是全部帶where子句的查詢都會顯示「Using where」。有時「Using where」的出現就是一個暗示:查詢可受益於不一樣的索引。
「Using temporary」
這意味着mysql在對查詢結果排序時會使用一個臨時表。
「Using filesort」
這意味着mysql會對結果使用一個外部索引排序,而不是按索引次序從表裏讀取行。mysql有兩種文件排序算法,這兩種排序方式均可以在內存或者磁盤上完成,explain不會告訴你mysql將使用哪種文件排序,也不會告訴你排序會在內存裏仍是磁盤上完成。
「Range checked for each record(index map: N)」
這個意味着沒有好用的索引,新的索引將在聯接的每一行上從新估算,N是顯示在possible_keys列中索引的位圖,而且是冗餘的
9、慢日誌記錄
開啓慢查詢日誌,可讓MySQL記錄下查詢超過指定時間的語句,經過定位分析性能的瓶頸,才能更好的優化數據庫系統的性能。
(1) 進入MySql 查詢是否開了慢查詢
show variables like 'slow_query%';
參數解釋:
slow_query_log 慢查詢開啓狀態 OFF 未開啓 ON 爲開啓
slow_query_log_file 慢查詢日誌存放的位置(這個目錄須要MySQL的運行賬號的可寫權限,通常設置爲MySQL的數據存放目錄)
(2)查看慢查詢超時時間
show variables like 'long%';
ong_query_time 查詢超過多少秒才記錄 默認10秒
(3)開啓慢日誌(1)(是否開啓慢查詢日誌,1表示開啓,0表示關閉。)
set global slow_query_log=1;
(4)再次查看
show variables like '%slow_query_log%';
(5)開啓慢日誌(2):(推薦)
在my.cnf 文件中
找到[mysqld]下面添加:
slow_query_log =1
slow_query_log_file=C:\mysql-5.6.40-winx64\data\localhost-slow.log
long_query_time = 1
參數說明:
slow_query_log 慢查詢開啓狀態 1 爲開啓
slow_query_log_file 慢查詢日誌存放的位置
long_query_time 查詢超過多少秒才記錄 默認10秒 修改成1秒
10、分頁性能相關方案
先回顧一下,如何取當前表中的前10條記錄,每十條取一次.......
第1頁:
select * from userinfo limit 0,10;
第2頁:
select * from userinfo limit 10,10;
第3頁:
select * from userinfo limit 20,10;
第4頁:
select * from userinfo limit 30,10;
......
第2000010頁
select * from userinfo limit 2000000,10;
PS:會發現,越日後查詢,須要的時間約長,是由於越日後查,全文掃描查詢,會去數據表中掃描查詢。
最優的解決方案
(1)只有上一頁和下一頁
作一個記錄:記錄當前頁的最大id或最小id
下一頁:
select * from userinfo where id>max_id limit 10;
上一頁:
select * from userinfo where id<min_id order by id desc limit 10;
(2) 中間有頁碼的狀況
select * from userinfo where id in(
select id from (select * from userinfo where id > pre_max_id limit (cur_max_id-pre_max_id)*10) as A order by A.id desc limit 10
);