1、數據庫是什麼?html
數據庫即存放數據的倉庫,只不過這個倉庫是在計算機存儲設備上,並且數據是按必定的格式存放的mysql
數據庫是長期存放在計算機內、有組織、可共享的數據,按必定的數據模型組織、描述和儲存,具備較小的冗餘度、較高的數據獨立性和易擴展性,並可爲各類 用戶共享。redis
數據庫本質就是一個C/S的套接字軟件 常見的數據庫:sql
關係型(關係型數據庫須要有表結構):如sqllite,db2,oracle,access,sql server,MySQL,注意:sql語句通用
非關係型(非關係型數據庫是key-value存儲的,沒有表結構):mongodb,redis,memcache
2、數據庫相關概念mongodb
數據庫服務器:運行有數據庫管理軟件的計算機數據庫
數據庫管理軟件mysql:就是一個套接字服務端vim
庫:就是一個文件夾 表:就是一個文件windows
記錄:就至關於文件中的一行內容(抽取事物一系列典型的特徵拼到一塊兒,)安全
數據:用於記錄現實世界中的某種狀態bash
三, 爲何要有數據庫
一、程序全部的組件就不可能運行在一臺機器上
由於這臺機器一旦掛掉則意味着整個軟件的崩潰,而且程序的執行效率依賴於承載它的硬件,而一臺機器機器的性能總歸是有限的,受限於目前的硬件水平,就一臺機器的性能垂直進行擴展是有極限的。
因而咱們只能經過水平擴展來加強咱們系統的總體性能,這就須要咱們將程序的各個組件分佈於多臺機器去執行。
二、數據安全問題
根據1的描述,咱們將程序的各個組件分佈到各臺機器,但需知各組件仍然是一個總體,言外之意,全部組件的數據仍是要共享的。但每臺機器上的組件都只能操做本機的文件,這就致使了數據必然不一致。
因而咱們想到了將數據與應用程序分離:把文件存放於一臺機器,而後將多臺機器經過網絡去訪問這臺機器上的文件(用socket實現),即共享這臺機器上的文件,共享則意味着競爭,會發生數據不安全,須要加鎖處理。。。。
三、併發
根據2的描述,咱們必須寫一個socket服務端來管理這臺機器(數據庫服務器)上的文件,而後寫一個socket客戶端,完成以下功能:
1.遠程鏈接(支持併發)
2.打開文件
3.讀寫(加鎖)
4.關閉文件
4、怎麼用
SQL語言主要用於存取數據、查詢數據、更新數據和管理關係數據庫系統,SQL語言由IBM開發。SQL語言分爲3種類型:
一、DDL語句 數據庫定義語言: 數據庫、表、視圖、索引、存儲過程,例如CREATE DROP ALTER
二、DML語句 數據庫操縱語言: 插入數據INSERT、刪除數據DELETE、更新數據UPDATE、查詢數據SELECT
三、DCL語句 數據庫控制語言: 例如控制用戶的訪問權限GRANT、REVOKE
1. 操做文件夾
增:create database db1 charset utf8;
查:show databases;
改:alter database db1 charset latin1;
刪除: drop database db1;
2. 操做文件
先切換到文件夾下:use db1
增:create table t1(id int,name char);
查:show tables
改:alter table t1 modify name char(3);
alter table t1 change name name1 char(2);
刪:drop table t1;
3. 操做文件中的內容/記錄
增:insert into t1 values(1,'egon1'),(2,'egon2'),(3,'egon3');
查:select * from t1;
改:update t1 set name='sb' where id=2;
刪:delete from t1 where id=1;
清空表:
delete from t1; #若是有自增id,新增的數據,仍然是以刪除前的最後同樣做爲起始。
truncate table t1;數據量大,刪除速度比上一條快,且直接從零開始,
auto_increment 表示:自增
primary key 表示:約束(不能重複且不能爲空);加速查找
庫相關操做
建立數據庫
1 語法(help create database)
CREATE DATABASE 數據庫名 charset utf8;
2 數據庫命名規則:
能夠由字母、數字、下劃線、@、#、$
區分大小寫
惟一性
不能使用關鍵字如 create select
不能單獨使用數字
最長128位
數據庫相關操做
1 查看數據庫
show databases;
show create database db1;
select database();
2 選擇數據庫
USE 數據庫名
3 刪除數據庫
DROP DATABASE 數據庫名;
4 修改數據庫
alter database db1 charset utf8;
表相關操做
存儲引擎介紹
數據庫中的表也應該有不一樣的類型,表的類型不一樣,會對應mysql不一樣的存取機制,表類型又稱爲存儲引擎。
存儲引擎說白了就是如何存儲數據、如何爲存儲的數據創建索引和如何更新、查詢數據等技術的實現方
法。由於在關係數據庫中數據的存儲是以表的形式存儲的,因此存儲引擎也能夠稱爲表類型(即存儲和
操做此表的類型)
建立表
語法:
create table 表名(
字段名1 類型[(寬度) 約束條件],
字段名2 類型[(寬度) 約束條件],
字段名3 類型[(寬度) 約束條件]
);
注意:
1. 在同一張表中,字段名是不能相同
2. 寬度和約束條件可選
3. 字段名和類型是必須的
查看錶結構
MariaDB [db1]> describe t1; 查看錶結構,可簡寫爲desc 表名
MariaDB [db1]> show create table t1\G; #查看錶詳細結構,可加\G
數據類型
存儲引擎決定了表的類型,而表內存放的數據也要有不一樣的類型,每種數據類型都有本身的寬度,但寬度是可選的
複製代碼
1. 數字:
整型:tinyinit int bigint 做用:存儲年齡,等級,id,各類號碼等
小數:做用:存儲薪資、身高、體重、體質參數等
float :在位數比較短的狀況下不精準
double :在位數比較長的狀況下不精準
0.000001230123123123
存成:0.000001230000
decimal:(若是用小數,則用推薦使用decimal)
精準
內部原理是以字符串形式去存
2. 字符串:
char(0-255):簡單粗暴,浪費空間,存取速度快
root存成root000000
varchar(0-65535):精準,節省空間,存取速度慢
sql優化:建立表時,定長的類型往前放,變長的日後放
好比性別 好比地址或描述信息
>255個字符,超了就把文件路徑存放到數據庫中。
好比圖片,視頻等找一個文件服務器,數據庫中只存路徑或url。
對於InnoDB數據表,內部的行存儲格式沒有區分固定長度和可變長度列(全部數據行都使用指向數據列值的頭指針),所以在本質上,
使用固定長度的CHAR列不必定比使用可變長度VARCHAR列性能要好。於是,主要的性能因素是數據行使用的存儲總量。
因爲CHAR平均佔用的空間多於VARCHAR,所以使用VARCHAR來最小化須要處理的數據行的存儲總量和磁盤I/O是比較好的。
3. 時間類型:
最經常使用:datetime
4. 枚舉類型 enum 單選 只能在給定的範圍內選一個值,如性別 sex 男male/女female
集合類型 set 多選 在給定的範圍內能夠選擇一個或一個以上的值(愛好1,愛好2,愛好3...)
表完整性約束
約束條件與數據類型的寬度同樣,都是可選參數
做用:用於保證數據的完整性和一致性
主要分爲:
PRIMARY KEY (PK) 標識該字段爲該表的主鍵,能夠惟一的標識記錄
FOREIGN KEY (FK) 標識該字段爲該表的外鍵
NOT NULL 標識該字段不能爲空
UNIQUE KEY (UK) 標識該字段的值是惟一的
AUTO_INCREMENT 標識該字段的值自動增加(整數類型,並且爲主鍵)
DEFAULT 爲該字段設置默認值
UNSIGNED 無符號
ZEROFILL 使用0填充
如何找出兩張表之間的關係
一、先站在左表的角度去找 是否左表的多條記錄能夠對應右表的一條記錄,若是是,則證實左表的一個字段foreign key 右表一個字段(一般是id) 二、再站在右表的角度去找 是否右表的多條記錄能夠對應左表的一條記錄,若是是,則證實右表的一個字段foreign key 左表一個字段(一般是id) 三、總結:
多對一:(一對多(或多對一):一個出版社能夠出版多本書 關聯方式:foreign key) 若是隻有步驟1成立,則是左表多對一右表 若是隻有步驟2成立,則是右表多對一左表 多對多 :(一個做者能夠寫多本書,一本書也能夠有多個做者,雙向的一對多,即多對多 關聯方式:foreign key+一張新的表) 若是步驟1和2同時成立,則證實這兩張表時一個雙向的多對一,即多對多,須要定義一個這兩張表的關係表來專門存放兩者的關係 一對一:(一個學生是一個客戶,一個客戶有可能變成一個學校,即一對一的關係 關聯方式:foreign key+unique) 若是1和2都不成立,而是左表的一條記錄惟一對應右表的一條記錄,反之亦然。這種狀況很簡單,就是在左表foreign key右表的基礎上,將左表的外鍵字段設置成unique便可
修改表ALTER TABLE
語法:
1. 修改表名
ALTER TABLE 表名
RENAME 新表名;
2. 增長字段
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…],
ADD 字段名 數據類型 [完整性約束條件…];
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…] FIRST;
ALTER TABLE 表名
ADD 字段名 數據類型 [完整性約束條件…] AFTER 字段名;
3. 刪除字段
ALTER TABLE 表名
DROP 字段名;
4. 修改字段
ALTER TABLE 表名
MODIFY 字段名 數據類型 [完整性約束條件…];
ALTER TABLE 表名
CHANGE 舊字段名 新字段名 舊數據類型 [完整性約束條件…];
ALTER TABLE 表名
CHANGE 舊字段名 新字段名 新數據類型 [完整性約束條件…];
示例:
1. 修改存儲引擎
mysql> alter table service
-> engine=innodb;
2. 添加字段
mysql> alter table student10
-> add name varchar(20) not null,
-> add age int(3) not null default 22;
mysql> alter table student10
-> add stu_num varchar(10) not null after name; //添加name字段以後
mysql> alter table student10
-> add sex enum('male','female') default 'male' first; //添加到最前面
3. 刪除字段
mysql> alter table student10
-> drop sex;
mysql> alter table service
-> drop mac;
4. 修改字段類型modify
mysql> alter table student10
-> modify age int(3);
mysql> alter table student10
-> modify id int(11) not null primary key auto_increment; //修改成主鍵
5. 增長約束(針對已有的主鍵增長auto_increment)
mysql> alter table student10 modify id int(11) not null primary key auto_increment;
ERROR 1068 (42000): Multiple primary key defined
mysql> alter table student10 modify id int(11) not null auto_increment;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
6. 對已經存在的表增長複合主鍵
mysql> alter table service2
-> add primary key(host_ip,port);
7. 增長主鍵
mysql> alter table student1
-> modify name varchar(10) not null primary key;
8. 增長主鍵和自動增加
mysql> alter table student1
-> modify id int not null primary key auto_increment;
9. 刪除主鍵
a. 刪除自增約束
mysql> alter table student10 modify id int(11) not null;
b. 刪除主鍵
mysql> alter table student10
-> drop primary key;
刪除表
DROP TABLE 表名;
記錄相關操做
在MySQL管理軟件中,能夠經過SQL語句中的DML語言來實現數據的操做,包括
- 使用INSERT實現數據的插入
- UPDATE實現數據的更新
- 使用DELETE實現數據的刪除
- 使用SELECT查詢數據以及。
插入數據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 …;
更新數據UPDATE
語法:
UPDATE 表名 SET
字段1=值1,
字段2=值2,
WHERE CONDITION;
示例:
UPDATE mysql.user SET password=password(‘123’)
where user=’root’ and host=’localhost’;
刪除數據DELETE
語法:
DELETE FROM 表名
WHERE CONITION;
示例:
DELETE FROM mysql.user
WHERE password=’’;
練習:
更新MySQL root用戶密碼爲mysql123
刪除除從本地登陸的root用戶之外的全部用戶
單表查詢
單表查詢的語法
SELECT 字段1,字段2... FROM 表名 WHERE 條件 GROUP BY field HAVING 篩選 ORDER BY field LIMIT 限制條數
關鍵字的執行優先級(重點)
重點中的重點:關鍵字的執行優先級
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
姓名 emp_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 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)
;
#ps:若是在windows系統中,插入中文字符,select的結果爲空白,能夠將全部字符編碼統一設置成gbk
準備表和記錄
#簡單查詢
SELECT id,name,sex,age,hire_date,post,post_comment,salary,office,depart_id
FROM employee;
SELECT * FROM employee;
SELECT name,salary FROM employee;
#避免重複DISTINCT
SELECT DISTINCT post FROM employee;
#經過四則運算查詢
SELECT name, salary*12 FROM employee;
SELECT name, salary*12 AS Annual_salary FROM employee;
SELECT name, salary*12 Annual_salary FROM employee;
#定義顯示格式
CONCAT() 函數用於鏈接字符串
SELECT CONCAT('姓名: ',name,' 年薪: ', salary*12) AS Annual_salary
FROM employee;
CONCAT_WS() 第一個參數爲分隔符
SELECT CONCAT_WS(':',name,salary*12) AS Annual_salary
FROM employee;
結合CASE語句:
SELECT
(
CASE
WHEN NAME = 'egon' THEN
NAME
WHEN NAME = 'alex' THEN
CONCAT(name,'_BIGSB')
ELSE
concat(NAME, 'SB')
END
) as new_name
FROM
emp;
WHERE約束
where字句中可使用:
1. 比較運算符:> < >= <= <> !=
2. between 80 and 100 值在10到20之間
3. in(80,90,100) 值是10或20或30
4. like 'egon%'
pattern能夠是%或_,
%表示任意多字符
_表示一個字符
5. 邏輯運算符:在多個條件直接可使用邏輯運算符 and or not
#1:單條件查詢
SELECT name FROM employee
WHERE post='sale';
#2:多條件查詢
SELECT name,salary FROM employee
WHERE post='teacher' AND salary>10000;
#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;
#4:關鍵字IS NULL(判斷某個字段是否爲NULL不能用等號,須要用IS)
SELECT name,post_comment FROM employee
WHERE post_comment IS NULL;
SELECT name,post_comment FROM employee
WHERE post_comment IS NOT NULL;
SELECT name,post_comment FROM employee
WHERE post_comment=''; 注意''是空字符串,不是null
ps:
執行
update employee set post_comment='' where id=2;
再用上條查看,就會有結果了
#5:關鍵字IN集合查詢
SELECT name,salary FROM employee
WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;
SELECT name,salary FROM employee
WHERE salary IN (3000,3500,4000,9000) ;
SELECT name,salary FROM employee
WHERE salary NOT IN (3000,3500,4000,9000) ;
#6:關鍵字LIKE模糊查詢
通配符’%’
SELECT * FROM employee
WHERE name LIKE 'eg%';
通配符’_’
SELECT * FROM employee
WHERE name LIKE 'al__';
分組查詢:GROUP BY
什麼是分組?爲何要分組?
#一、首先明確一點:分組發生在where以後,即分組是基於where以後獲得的記錄而進行的
#二、分組指的是:將全部記錄按照某個相同字段進行歸類,好比針對員工信息表的職位分組,或者按照性別進行分組等
#三、爲什麼要分組呢?
取每一個部門的最高工資
取每一個部門的員工數
取男人數和女人數
小竅門:‘每’這個字後面的字段,就是咱們分組的依據
#四、大前提:
能夠按照任意字段分組,可是分組完畢後,好比group by post,只能查看post字段,若是想查看組內信息,須要藉助於聚合函數
單獨使用GROUP BY關鍵字分組
SELECT post FROM employee GROUP BY post;
注意:咱們按照post字段分組,那麼select查詢的字段只能是post,想要獲取組內的其餘相關信息,須要藉助函數
GROUP BY關鍵字和GROUP_CONCAT()函數一塊兒使用
SELECT post,GROUP_CONCAT(name) FROM employee GROUP BY post;#按照崗位分組,並查看組內成員名
SELECT post,GROUP_CONCAT(name) as emp_members FROM employee GROUP BY post;
GROUP BY與聚合函數一塊兒使用
select post,count(id) as count from employee group by post;#按照崗位分組,並查看每一個組有多少人
強調:
若是咱們用unique的字段做爲分組的依據,則每一條記錄自成一組,這種分組沒有意義 多條記錄之間的某個字段值相同,該字段一般用來做爲分組的依據
聚合函數
#強調:聚合函數聚合的是組的內容,如果沒有分組,則默認一組
示例:
SELECT COUNT(*) FROM employee;
SELECT COUNT(*) FROM employee WHERE depart_id=1;
SELECT MAX(salary) FROM employee;
SELECT MIN(salary) FROM employee;
SELECT AVG(salary) FROM employee;
SELECT SUM(salary) FROM employee;
SELECT SUM(salary) FROM employee WHERE depart_id=3;
多表查詢
多表鏈接查詢
#重點:外連接語法 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 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| 5 | liwenzhou | male | 18 | 200 | 201 | 人力資源 |
| 5 | liwenzhou | male | 18 | 200 | 202 | 銷售 |
| 5 | liwenzhou | male | 18 | 200 | 203 | 運營 |
| 6 | jingliyang | female | 18 | 204 | 200 | 技術 |
| 6 | jingliyang | female | 18 | 204 | 201 | 人力資源 |
| 6 | jingliyang | female | 18 | 204 | 202 | 銷售 |
| 6 | jingliyang | 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 | liwenzhou | 18 | male | 技術 |
+----+-----------+------+--------+--------------+
#上述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 | liwenzhou | 技術 |
| 2 | alex | 人力資源 |
| 3 | wupeiqi | 人力資源 |
| 4 | yuanhao | 銷售 |
| 6 | jingliyang | NULL |
+----+------------+--------------+
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 | liwenzhou | 技術 |
| NULL | NULL | 運營 |
+------+-----------+--------------+
全外鏈接:顯示左右兩個表所有記錄
全外鏈接:在內鏈接的基礎上增長左邊有右邊沒有的和右邊有左邊沒有的結果
#注意:mysql不支持全外鏈接 full JOIN
#強調: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 | liwenzhou | male | 18 | 200 | 200 | 技術 |
| 2 | alex | female | 48 | 201 | 201 | 人力資源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力資源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 銷售 |
| 6 | jingliyang | female | 18 | 204 | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | 203 | 運營 |
+------+------------+--------+------+--------+------+--------------+
#注意 union與union all的區別:union會去掉相同的紀錄
符合條件鏈接查詢
#示例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;
子查詢
#1:子查詢是將一個查詢語句嵌套在另外一個查詢語句中。 #2:內層查詢語句的查詢結果,能夠爲外層查詢語句提供查詢條件。 #3:子查詢中能夠包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字 #4:還能夠包含比較運算符:= 、 !=、> 、<等
帶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人的部門名(子查詢獲得的是有人的部門id)
select name from department where id not in (select distinct dep_id from employee);
帶比較運算符的子查詢
#比較運算符:=、!=、>、>=、<、<=、<>
#查詢大於全部人平均年齡的員工名與年齡
mysql> select name,age from emp where age > (select avg(age) from emp);
+---------+------+
| name | age |
+---------+------+
| alex | 48 |
| wupeiqi | 38 |
+---------+------+
rows in set (0.00 sec)
#查詢大於部門內平均年齡的員工名、年齡
select t1.name,t1.age from emp t1
inner join
(select dep_id,avg(age) avg_age from emp group by dep_id) t2
on t1.dep_id = t2.dep_id
where t1.age > t2.avg_age;
帶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 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | 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)
權限管理
#受權表
user #該表放行的權限,針對:全部數據,全部庫下全部表,以及表下的全部字段
db #該表放行的權限,針對:某一數據庫,該數據庫下的全部表,以及表下的全部字段
tables_priv #該表放行的權限。針對:某一張表,以及該表下的全部字段
columns_priv #該表放行的權限,針對:某一個字段
#按圖解釋:
user:放行db1,db2及其包含的全部
db:放行db1,及其db1包含的全部
tables_priv:放行db1.table1,及其該表包含的全部
columns_prive:放行db1.table1.column1,只放行該字段
數據備份、pymysql模塊
生產環境仍是推薦使用mysql命令行,但爲了方便咱們測試,可使用IDE工具
下載連接:https://pan.baidu.com/s/1bpo5mqj
MySQL數據備份
#1. 物理備份: 直接複製數據庫文件,適用於大型數據庫環境。但不能恢復到異構系統中如Windows。 #2. 邏輯備份: 備份的是建表、建庫、插入等操做所執行SQL語句,適用於中小型數據庫,效率相對較低。 #3. 導出表: 將表導入到文本文件中。
1、使用mysqldump實現邏輯備份
#語法:
# mysqldump -h 服務器 -u用戶名 -p密碼 數據庫名 > 備份文件.sql
#示例:
#單庫備份
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql
#多庫備份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql
#備份全部庫
mysqldump -uroot -p123 --all-databases > all.sql
2、恢復邏輯備份
#方法一:
[root@egon backup]# mysql -uroot -p123 < /backup/all.sql
#方法二:
mysql> use db1;
mysql> SET SQL_LOG_BIN=0;
mysql> source /root/db1.sql
#注:若是備份/恢復單個庫時,能夠修改sql文件
DROP database if exists school;
create database school;
use school;
備份/恢復案例
#數據庫備份/恢復實驗一:數據庫損壞
備份:
1. # mysqldump -uroot -p123 --all-databases > /backup/`date +%F`_all.sql
2. # mysql -uroot -p123 -e 'flush logs' //截斷併產生新的binlog
3. 插入數據 //模擬服務器正常運行
4. mysql> set sql_log_bin=0; //模擬服務器損壞
mysql> drop database db;
恢復:
1. # mysqlbinlog 最後一個binlog > /backup/last_bin.log
2. mysql> set sql_log_bin=0;
mysql> source /backup/2014-02-13_all.sql //恢復最近一次徹底備份
mysql> source /backup/last_bin.log //恢復最後個binlog文件
#數據庫備份/恢復實驗二:若是有誤刪除
備份:
1. mysqldump -uroot -p123 --all-databases > /backup/`date +%F`_all.sql
2. mysql -uroot -p123 -e 'flush logs' //截斷併產生新的binlog
3. 插入數據 //模擬服務器正常運行
4. drop table db1.t1 //模擬誤刪除
5. 插入數據 //模擬服務器正常運行
恢復:
1. # mysqlbinlog 最後一個binlog --stop-position=260 > /tmp/1.sql
# mysqlbinlog 最後一個binlog --start-position=900 > /tmp/2.sql
2. mysql> set sql_log_bin=0;
mysql> source /backup/2014-02-13_all.sql //恢復最近一次徹底備份
mysql> source /tmp/1.log //恢復最後個binlog文件
mysql> source /tmp/2.log //恢復最後個binlog文件
注意事項:
1. 徹底恢復到一個乾淨的環境(例如新的數據庫或刪除原有的數據庫)
2. 恢復期間全部SQL語句不該該記錄到binlog中
實現自動化備份
備份計劃:
1. 什麼時間 2:00
2. 對哪些數據庫備份
3. 備份文件放的位置
備份腳本:
[root@egon ~]# vim /mysql_back.sql
#!/bin/bash
back_dir=/backup
back_file=`date +%F`_all.sql
user=root
pass=123
if [ ! -d /backup ];then
mkdir -p /backup
fi
# 備份並截斷日誌
mysqldump -u${user} -p${pass} --events --all-databases > ${back_dir}/${back_file}
mysql -u${user} -p${pass} -e 'flush logs'
# 只保留最近一週的備份
cd $back_dir
find . -mtime +7 -exec rm -rf {} \;
手動測試:
[root@egon ~]# chmod a+x /mysql_back.sql
[root@egon ~]# chattr +i /mysql_back.sql
[root@egon ~]# /mysql_back.sql
配置cron:
[root@egon ~]# crontab -l
* * * /mysql_back.sql
表的導出和導入
SELECT... INTO OUTFILE 導出文本文件
示例:
mysql> SELECT * FROM school.student1
INTO OUTFILE 'student1.txt'
FIELDS TERMINATED BY ',' //定義字段分隔符
OPTIONALLY ENCLOSED BY '」' //定義字符串使用什麼符號括起來
LINES TERMINATED BY '\n' ; //定義換行符
mysql 命令導出文本文件
示例:
# mysql -u root -p123 -e 'select * from student1.school' > /tmp/student1.txt
# mysql -u root -p123 --xml -e 'select * from student1.school' > /tmp/student1.xml
# mysql -u root -p123 --html -e 'select * from student1.school' > /tmp/student1.html
LOAD DATA INFILE 導入文本文件
mysql> DELETE FROM student1;
mysql> LOAD DATA INFILE '/tmp/student1.txt'
INTO TABLE school.student1
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '」'
LINES TERMINATED BY '\n';
#可能會報錯 mysql> select * from db1.emp into outfile 'C:\\db1.emp.txt' fields terminated by ',' lines terminated by '\r\n'; ERROR 1238 (HY000): Variable 'secure_file_priv' is a read only variable #數據庫最關鍵的是數據,一旦數據庫權限泄露,那麼經過上述語句就能夠輕鬆將數據導出到文件中而後下載拿走,於是mysql對此做了限制,只能將文件導出到指定目錄 在配置文件中 [mysqld] secure_file_priv='C:\\' #只能將數據導出到C:\\下 重啓mysql 從新執行上述語句
數據庫遷移
務必保證在相同版本之間遷移 # mysqldump -h 源IP -uroot -p123 --databases db1 | mysql -h 目標IP -uroot -p456
execute()之sql注入
注意:符號--會註釋掉它以後的sql,正確的語法:--後至少有一個任意字符
根本原理:就根據程序的字符串拼接name='%s',咱們輸入一個xxx' -- haha,用咱們輸入的xxx加'在程序中拼接成一個判斷條件name='xxx' -- haha'
最後那一個空格,在一條sql語句中若是遇到select * from t1 where id > 3 -- and name='egon';則--以後的條件被註釋掉了
#一、sql注入之:用戶存在,繞過密碼
egon' -- 任意字符
#二、sql注入之:用戶不存在,繞過用戶與密碼
xxx' or 1=1 -- 任意字符
# 原來是咱們對sql進行字符串拼接
# sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd)
# print(sql)
# res=cursor.execute(sql)
#改寫爲(execute幫咱們作字符串拼接,咱們無需且必定不能再爲%s加引號了)
sql="select * from userinfo where name=%s and password=%s" #!!!注意%s須要去掉引號,由於pymysql會自動爲咱們加上
res=cursor.execute(sql,[user,pwd]) #pymysql模塊自動幫咱們解決sql注入的問題,只要咱們按照pymysql的規矩來。
增、刪、改:conn.commit()
import pymysql
#連接
conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
#遊標
cursor=conn.cursor()
#執行sql語句
#part1
# sql='insert into userinfo(name,password) values("root","123456");'
# res=cursor.execute(sql) #執行sql語句,返回sql影響成功的行數
# print(res)
#part2
# sql='insert into userinfo(name,password) values(%s,%s);'
# res=cursor.execute(sql,("root","123456")) #執行sql語句,返回sql影響成功的行數
# print(res)
#part3
sql='insert into userinfo(name,password) values(%s,%s);'
res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #執行sql語句,返回sql影響成功的行數
print(res)
conn.commit() #提交後才發現表中插入記錄成功
cursor.close()
conn.close()
查:fetchone,fetchmany,fetchall
import pymysql
#連接
conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
#遊標
cursor=conn.cursor()
#執行sql語句
sql='select * from userinfo;'
rows=cursor.execute(sql) #執行sql語句,返回sql影響成功的行數rows,將結果放入一個集合,等待被查詢
# cursor.scroll(3,mode='absolute') # 相對絕對位置移動
# cursor.scroll(3,mode='relative') # 相對當前位置移動
res1=cursor.fetchone()
res2=cursor.fetchone()
res3=cursor.fetchone()
res4=cursor.fetchmany(2)
res5=cursor.fetchall()
print(res1)
print(res2)
print(res3)
print(res4)
print(res5)
print('%s rows in set (0.00 sec)' %rows)
conn.commit() #提交後才發現表中插入記錄成功
cursor.close()
conn.close()
'''
(1, 'root', '123456')
(2, 'root', '123456')
(3, 'root', '123456')
((4, 'root', '123456'), (5, 'root', '123456'))
((6, 'root', '123456'), (7, 'lhf', '12356'), (8, 'eee', '156'))
rows in set (0.00 sec)
'''
獲取插入的最後一條數據的自增ID
import pymysql
conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
cursor=conn.cursor()
sql='insert into userinfo(name,password) values("xxx","123");'
rows=cursor.execute(sql)
print(cursor.lastrowid) #在插入語句後查看
conn.commit()
cursor.close()
conn.close()
視圖、觸發器、事務、存儲過程、函數
視圖
視圖是一個虛擬表(非真實存在),其本質是【根據SQL語句獲取動態的數據集,併爲其命名】,用戶使用時只需使用【名稱】便可獲取結果集,能夠將該結果集當作表來使用。
使用視圖咱們能夠把查詢過程當中的臨時表摘出來,用視圖去實現,這樣之後再想操做該臨時表的數據時就無需重寫複雜的sql了,直接去視圖中查找便可,但視圖有明顯地效率問題,而且視圖是存放在數據庫中的,若是咱們程序中使用的sql過度依賴數據庫中的視圖,即強耦合,那就意味着擴展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 視圖名稱 AS SQL語句
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)
#!!!注意注意注意:
#1. 使用視圖之後就無需每次都重寫子查詢的sql,可是這麼效率並不高,還不如咱們寫子查詢的效率高
#2. 並且有一個致命的問題:視圖是存放到數據庫裏的,若是咱們程序中的sql過度依賴於數據庫中存放的視圖,那麼意味着,一旦sql須要修改且涉及到視圖的部分,則必須去數據庫中進行修改,而一般在公司中數據庫有專門的DBA負責,你要想完成修改,必須付出大量的溝通成本DBA可能纔會幫你完成修改,極其地不方便
使用視圖
#修改視圖,原始表也跟着改
mysql> select * from course;
+-----+--------+------------+
| cid | cname | teacher_id |
+-----+--------+------------+
| 1 | 生物 | 1 |
| 2 | 物理 | 2 |
| 3 | 體育 | 3 |
| 4 | 美術 | 2 |
+-----+--------+------------+
rows in set (0.00 sec)
mysql> create view course_view as select * from course; #建立表course的視圖
Query OK, 0 rows affected (0.52 sec)
mysql> select * from course_view;
+-----+--------+------------+
| cid | cname | teacher_id |
+-----+--------+------------+
| 1 | 生物 | 1 |
| 2 | 物理 | 2 |
| 3 | 體育 | 3 |
| 4 | 美術 | 2 |
+-----+--------+------------+
rows in set (0.00 sec)
mysql> update course_view set cname='xxx'; #更新視圖中的數據
Query OK, 4 rows affected (0.04 sec)
Rows matched: 4 Changed: 4 Warnings: 0
mysql> insert into course_view values(5,'yyy',2); #往視圖中插入數據
Query OK, 1 row affected (0.03 sec)
mysql> select * from course; #發現原始表的記錄也跟着修改了
+-----+-------+------------+
| cid | cname | teacher_id |
+-----+-------+------------+
| 1 | xxx | 1 |
| 2 | xxx | 2 |
| 3 | xxx | 3 |
| 4 | xxx | 2 |
| 5 | yyy | 2 |
+-----+-------+------------+
rows in set (0.00 sec)
咱們不該該修改視圖中的記錄,並且在涉及多個表的狀況下是根本沒法修改視圖中的記錄的,以下圖
修改視圖
語法: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)
刪除視圖
語法:DROP VIEW 視圖名稱 DROP VIEW teacher_view
觸發器
使用觸發器能夠定製用戶對錶進行【增、刪、改】操做時先後的行爲,注意:沒有查詢
建立觸發器
# 插入前
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 cmd (
id INT PRIMARY KEY auto_increment,
USER CHAR (32),
priv CHAR (10),
cmd CHAR (64),
sub_time datetime, #提交時間
success enum ('yes', 'no') #0表明執行失敗
);
CREATE TABLE errlog (
id INT PRIMARY KEY auto_increment,
err_cmd CHAR (64),
err_time datetime
);
#建立觸發器
delimiter //
CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW
BEGIN
IF NEW.success = 'no' THEN #等值判斷只有一個等號
INSERT INTO errlog(err_cmd, err_time) VALUES(NEW.cmd, NEW.sub_time) ; #必須加分號
END IF ; #必須加分號
END//
delimiter ;
#往表cmd中插入記錄,觸發觸發器,根據IF的條件決定是否插入錯誤日誌
INSERT INTO cmd (
USER,
priv,
cmd,
sub_time,
success
)
VALUES
('egon','0755','ls -l /etc',NOW(),'yes'),
('egon','0755','cat /etc/passwd',NOW(),'no'),
('egon','0755','useradd xxx',NOW(),'no'),
('egon','0755','ps aux',NOW(),'yes');
#查詢錯誤日誌,發現有兩條
mysql> select * from errlog;
+----+-----------------+---------------------+
| id | err_cmd | err_time |
+----+-----------------+---------------------+
| 1 | cat /etc/passwd | 2017-09-14 22:18:48 |
| 2 | useradd xxx | 2017-09-14 22:18:48 |
+----+-----------------+---------------------+
rows in set (0.00 sec)
特別的:NEW表示即將插入的數據行,OLD表示即將刪除的數據行。
使用觸發器
觸發器沒法由用戶直接調用,而知因爲對錶的【增/刪/改】操做被動引起的。
刪除觸發器
drop trigger tri_after_insert_cmd;