40 - 數據庫基礎


1 數據庫概述

        數據庫指的是按照數據結構來組織、存儲、管理數據的倉庫,常用的數據庫種類為關系型數據庫和非關系型數據庫。關系型數據庫模型是把復雜的數據歸結為簡單的二元關系(即二維表格形式——)。
        在關系數據庫中,對數據的操作幾乎全部建立在一個或多個關系表格上,通過對這些關聯的表格分類、合並、連接或選取等運算實現數據的管理。
常見的數據庫有MySQL

1.1 關系數據庫之ACID理論

        ACID,指數據庫事務正確執行的四個基本要素的縮寫。包含:原子性(Atomicity)一致性(Consistency)隔離性(Isolation)持久性(Durability)。一個支持事務(Transaction)的數據庫,必須要具有這四種特性,否則在事務過程(Transaction processing)當中無法保證數據的正確性,交易過程極可能達不到交易方的要求。MySQL的Innode支持事務,所以它遵守ACID原則。

特性 描述
原子性(atomicity) 一個事務是一個不可分割的工作單位,事務中包括的所有操作要么全部做完,要么什么都不做
一致性(consistency) 事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的
隔離性(isolation) 一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對並發的其他事務是隔離的,並發執行的各個事務之間不能互相干擾
持久性(durability) 持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響

1.2 關系數據庫之概念

在關系數據庫中,關系就是二維表,由行和列組成。

  • 行row,也稱為記錄Record、元組。
  • 列Column,也稱為字段Filed、屬性。
  • 域Domain,叫做字段的取值范圍 。例如gender字段的取值就是M或者F兩個值。

其他概念性的東西:

  • 維數:關系的維數指關系中屬性的個數
  • 基數:元組的個數

注意在關系中,屬性的順序並不重要。理論上,元組順序也不重要,但是由於元組順序與存儲相關,會影響查詢效率。

1.2.1 候選鍵

關系中,能唯一標識一條元組(記錄)的屬性或屬性集合,成為候選鍵可以是多個字段的組合。
houxuan

1.2.2 主鍵

表示一列或者多列組成唯一的key,也就是通過這一個或者多個列能唯一的標識一條記錄。即被選擇的候選鍵。

  • 主鍵的列不能包含空值null。主鍵往往設置為整型、長整型,且自增AUTO_INCREMENT。
  • 表中可以沒有主鍵,但是一般表設計中,往往都會有主鍵,以免記錄重復
  • 功能主要在於查數據、定位數據

zhujian

1.2.3 外鍵

嚴格來說,當一個關系中的某個屬性或屬性的集合與另一個關系(也可以是自身)的候選鍵匹配時,就稱作這個屬性或屬性集合的外鍵。

  • 簡單來說,就是A表的某個字段數據來源於B表的主鍵(候選鍵)。
  • 外鍵約束,和外鍵不約束。 約束時,字段數據必須來源於關聯表的主鍵(候選鍵)

雖然可以關聯自己,但是並不常用

waijian

員工表的FK_depet_no字段就是員工表的外鍵。

1.2.4 約束Constraint

為了保證數據的完整正確,數據模型還必須有完整性約束。必須有值約束,某些列的值必須有值,不許為空null。

  • 域約束Domain Constraint:限定了表中字段的取值范圍 -- (一般在代碼中判斷)
  • 實體完整性Entity Integrity:PRIMARY KEY約束定義了主鍵,就定義了主鍵約束。主鍵不重復且唯一,不能為空。
  • 引用完整性Referential Integrity:外鍵定義中,可以不是引用另一張表的主鍵(可以是任意字段),但往往實際只會關注引用主鍵。
    • 插入規則:如果在表B插入一條記錄,B的外鍵列的數據,必須是表A中存在的主鍵值。(自動生效,不需要指定)
    • 更新規則:定義外鍵約束時指定該規則。
    • 刪除規則:定義外鍵約束時指定該規則。

更新規則和刪除規則,可選項如下:

  • CASCADE:級聯刪除,刪除被關聯數據時,從表關聯的數據全部刪除。
  • SET NULL:從父表刪除或更新行,會設置子表中的外鍵列為NULL,但必須保證子表沒有指定 NOT NULL,也就是說子表的字段可以為NULL才行。
  • RESTRICT:如果從父表刪除主鍵,如果子表引用了,則拒絕對父表的刪除或更新操作。(保護數據)
  • NO ACTION:表中SQL的關鍵字,在MySQL中與RESTRICT相同。拒絕對父表的刪除或更新操作。

外鍵約束,是為了保證數據完整性、一致性、杜絕數據冗余、數據錯誤。

建議先使用,等到連接的非常深入時,再使用代碼邏輯來解決外鍵約束關系。

1.2.5 索引

可以看作是一本字典的目錄,為了快速檢索用的。空間換時間,顯著提高查詢效率。可以對一列或者多列字段設定索引。(B+樹)

  • 主鍵索引(PRIMARY):主鍵會自動建立主鍵索引,主鍵本身就是為了快速定位唯一記錄。
  • 唯一索引(UNIQUE):表中的索引列組成的索引必須唯一,但可以為空,非控制必須唯一。
  • 普通索引(KEY):沒有唯一性的要求,就是建了一個字典的目錄而已。

1.3 實體聯系

首先來看一下實體和聯系:

  • 實體Entity:現實世界中具有相同屬性的一組對象,可以是物理存在的事物或抽象的事物。
  • 聯系Relationship:實體之間的關聯集合。

總結一下:

  • 實體在數據庫中就是一個一個表
  • 聯系在數據庫中就是記錄與記錄的對應關系

在關系型數據庫中實體主要有以下三種聯系:

類型 描述 解決方法
一對多聯系
1:n
一個員工屬於一個部門,一個部門有多個員工 員工外鍵
部門主鍵
多對多聯系
m:n
一個員工屬於多個部門,一個部門有多個員工 建立第三表
一對一聯系
1:1
假設有實體管理者,一個管理者管理一個部門,一個部門只有一個管理者 字段建在哪張表都行

一對一很少用。

1.4 視圖

視圖、也稱虛表、開起來很像表。它是由查詢語句生成的。可以通過視圖進行CRUD操作。
作用:

  1. 簡化操作,將復雜查詢SQL語句定義為視圖,可以簡化查詢。
  2. 數據安全,視圖可以只顯示真實表的部分列,或計算后的記過,從而隱藏真實表的數據

2 SQL

        Structured Query Language,是一種對關系數據庫中的數據進行定義和操作的語言方法,是大多數關系數據庫管理系統所支持的工業標准。

2.1 分類

  • 數據查詢語言(DQL):data query language,也成為數據檢索語句,作用是從表格中獲取數據,確定數據怎么樣在應用程序給出。關鍵字select是SQL用的最多的動詞,其他DQL常用的保留字段有where、order by、group by和having
  • 數據操作語言(DML):data manipulation language,其中包括動詞insert、update和delete,他們用於添加、修改、刪除表中的行,也稱動作查詢語句。
  • 數據處理語言(TPL):它的語句能確保被DML語句影響的表的所有行及時得以更新。TPL語句包括,begin、transaction、commit和rollback
  • 數據控制語言(DCL):data control languag,它的語句通過grant或revoke 獲得許可,確定 單個用戶和用戶組對數據庫對象的訪問。某些RDBMS可用GRANT或revoke控制對單個列的訪問。
  • 指針控制語言(CCL):它的語句,像 declare cursor、fetch into、update where current用於對一個或多個表單獨執行的操作
  • 數據定義語言(DDL):data definition language,其語句包括create和drop、alter。在數據庫中創建新表或刪除表(create table 或者 drop table),為表加入索引等。是動作查詢的一部分

我們日常開發會用到的SQL語言類型為:DML、DQL以及DDL

RDBMS的數據庫、表的概念其實就相當於目錄,文件,及內容

2.2 規范

編寫SQL語句時,我們要遵頊如下規范:

  1. SQL語句大小寫不敏感(一般建議,SQL的關鍵字、函數等大寫)
  2. SQL語句末尾應該使用分號結束
  3. 注釋
    • 多行注釋 /*注釋內容*/
    • 單行注釋 --注釋內容
    • MySQL 注釋可以使用 #
  4. 使用空格或縮進來提高可讀性
  5. 命名規范
    • 必須以字母開頭
    • 可以使用數字、#、$和_
    • 不可使用關鍵字

3 MySQL

MySQL是Web世界中使用最廣泛的數據庫服務器,訪問及管理mysql數據庫的最常用標准化語言為SQL結構化查詢語句。早先的MySQL使用的是MyISAM引擎,它是一種利用索引順序存取數據的軟件。從MySQL 4.0版本開始支持InnoDB引擎。

  • MyISAM,不支持事物,插入、查詢速度快
  • InnoDB:支持事務,行級鎖,MySQL 5.5起的默認引擎

3.1 安裝MySQL

這里僅列出在Linux下的安裝:

  • 通過yum進行安裝
1、安裝MySQL
yum install -y mysql-server (centos 7以下)
yum install -y mariadb-server (centos 7及以上)

2、啟動服務
/etc/init.d/mysqld start (centos 7以下)
systemctl start maridab (centos 7及以上)

3、關閉服務
/etc/init.d/mysqld stop (centos 7以下)
systemctl stop maridab (centos 7及以上)
  • 編譯安裝
1.安裝依賴包
yum install -y ncurses-devel libaio-devel
rpm -qa ncurses-devel libaio-devel

2.安裝cmake編譯工具
yum install -y cmake

3.上傳源碼包
rz -y mysql-5.5.49.tar.gz

4.解壓並安裝
tar xf mysql-5.5.49.tar.gz
cd mysql-5.5.49
 
cmake . -DCMAKE_INSTALL_PREFIX=/application/mysql-5.5.49 \
-DMYSQL_DATADIR=/application/mysql-5.5.49/data \
-DMYSQL_UNIX_ADDR=/application/mysql-5.5.49/tmp/mysql.sock \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=gbk,gb2312,utf8,ascii \
-DENABLED_LOCAL_INFILE=ON \
-DWITH_INNOBASE_STORAGE_ENAINE=1 \
-DWITH_FEDERATED_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 \
-DWITHOUT_PARTITION_STORAGE_ENGINE=1 \
-DWITH_FAST_MUTEXES=1 \
-DWITH_ZLIB=bundled \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_EMBEDDED_SERVER=1 \
-DWITH_DEBUG=0
 
make && make install && cd ..
5.創建鏈接文件
ln -s /application/mysql-5.5.49/ /application/mysql

6.創建數據庫用戶及配置文件
useradd -M -s /sbin/nologin mysql

7.初始化數據庫
/application/mysql/scripts/mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/application/mysql/data

8.定義環境變量
cp /application/mysql/bin/* /usr/local/sbin
或者
PATH=/application/mysql/bin:$PATH

9.開啟數據庫
/application/mysql/bin/mysql start

10.登錄數據庫
mysql
如果設置了用戶密碼
mysql -uroot -p123456

11.關閉數據庫
/application/mysql/bin/mysql stop

12.設置密碼
mysqladmin password 123456 -S /data/3306/mysql.sock

3.2 數據類型

MySQL的數據類型:

類型 含義
tinyint 1字節,帶符號的范圍是-128到127。無符號的范圍是0到255。bool或boolean,就是tinyint,0表示假,非0表示真
smallint 2字節,帶符號的范圍是-32768到32767。無符號的范圍是0到65535
int 整型,4字節,同Integer,帶符號的范圍是-2147483648到2147483647。無符號的范圍是0到4294967295
bigint 長整型,8字節,帶符號的范圍是-9223372036854775808到9223372036854775807。無符號的范圍是0到18446744073709551615
float 單精度浮點數精確到大約7位小數位
double 雙精度浮點數精確到大約15位小數位
DATE 日期。支持的范圍為'1000-01-01'到'9999-12-31'
DATETIME 支持的范圍是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'
TIMESTAMP 時間戳。范圍是'1970-01-01 00:00:00'到2037年
char(M) 固定長度,右邊填充空格以達到長度要求。M為長度,范圍為0~255。M指的是字符個數
varchar(M) 變長字符串。M 表示最大列長度。M的范圍是0到65,535。但不能突破行最大字節數65535
text 大文本。最大長度為65535(2^16-1)個字符
BLOB 大字節。最大長度為65535(2^16–1)字節的BLOB列

BLOG:字節類型,存圖片,存二進制文件,能不用則不用,只會用一個字符串來存圖片的位置

3.4 用戶及授權操作

授權用戶:grant語句,取消權限:revoke語句

grant all on *.* to 'dahl'@'10.0.0.13' identified by '123456';
revoke all on *.* from dahl;
  • all:表示所有權限
  • *.*:表示所有庫的所有表
  • 'dah'@'10.0.0.13':表示用戶名,和登陸的IP地址,%為通配符,可以表示任意地址

刪除用戶:

drop user dahl;

3.5 庫操作

數據庫在文件系統上就是用目錄體現的,所以對庫的操作,可以理解為對目錄的操作。創建數據庫,會在MySQL的data目錄下創建同名文件夾

3.5.1 創建數據庫

語法格式:create database 數據庫名稱

create database db_name;
create database db_name default charset utf8;
create database if not exists db_name character set utf8;
create database if not exists db_name character set utf8mb4 collater utf8mb4_general_ci;
  • character set:指定字符集。
  • utf8mb4:是utf8的擴展,支持4字節utf8mb4,需要mysql5.5.3+
  • collate:指定字符串的校隊規則,用來做字符串的比較的。例如a、A誰大

3.5.2 刪除數據庫

語法格式:drop database 數據庫名稱

drop database db_name;

刪除數據庫目錄,注意會刪除庫下的所有表文件

3.5.3 其他操作

查看數據庫中存在的數據庫

show databases;

使用(切換)當前使用的數據庫(激活show tables語句)

use db_name;

查看創建庫的信息

show create database test;

3.6 表操作

表在文件系統上是用文件體現的,所以對表的操作,可以理解為對文件的操作。

創建表,會在對應的庫目錄下創建表空間文件

3.6.1 創建單表

create table user_info(
    id int not null auto_increment primary key,
    name char(20),
    age int,
    gender char(1),
    deparment_id int,
    constraint 約束名稱 foreign key(deparment_id) references dep_info(id)
)engine = innodb default charset=utf8;
 
--> 語法格式:
--> create table 表名(
-->      列名  類型  [是否為空] [是否默認值] [自增] [主鍵]  ,
-->      列名2  類型
-->      .... ....
-->      [ constraint 外鍵名稱 foreign key(本表的被約束字段) reference 目標表名(字段) ]      
--> ) engine = 存儲引擎名稱 default charset = utf8;

各字段含義:

  • 列名
  • 數據類型
  • 是否可以為空(null/not null)
  • 是否默認值(default value)
  • 是否自增(auto_icrement):一個表只能存在一個自增列並且必須有索引(普通索引或主鍵索引),類型必須是數值型。
  • 主鍵(primarr key):數據不能為空、不能重復,可以加速查找(數據庫的B樹結構)
  • 外鍵(constraint) :對表內某字段的內容進行約束,必須是某個表的某個字段已有的值,含外鍵的表可以理解為1對多,注意外鍵關聯的兩個字段數據類型要一致 

3.6.2 創建多表外鍵關聯

  • 一對多:一個表的某個字段的數據來自於另一個表已存在的數據。
  • 多對多:一個表的某幾個字段的數據來自於另一個或幾個表已存在的數據。

一對多:

CREATE TABLE user_info (
	id INT NOT NULL auto_increment PRIMARY KEY,
	NAME CHAR (20),
	age INT,
	gender CHAR (1),
	deparment_id INT,
	CONSTRAINT 約束名稱 FOREIGN KEY (deparment_id) REFERENCES dep_info (id)
) ENGINE = INNODB DEFAULT charset = utf8;

CREATE TABLE dep_info (
	id INT NOT NULL auto_increment PRIMARY KEY,
	title CHAR (32),
) ENGINE = innode DEFAULT charset = utf8;

多對多:需要關系表來表明多對多關系

CREATE TABLE `boy` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
CREATE TABLE `girl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
CREATE TABLE `b2g` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `b_id` int(11) DEFAULT NULL,
  `g_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_b` (`b_id`),
  KEY `FK_G` (`g_id`),
  CONSTRAINT 約束名稱1 FOREIGN KEY (`b_id`) REFERENCES `boy` (`id`),
  CONSTRAINT 約束名稱2 FOREIGN KEY (`g_id`) REFERENCES `girl` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.6.3 刪除表

drop table tb_name;

3.6.4 查看表結構

desc table_name [ col_name ]

如果添加列明,表示查看表中某一列的結構。

3.6.4 其他操作

查看創建表的語句

show create table table_name;

查看當前庫的所有表

show tables;

3.7 操作表數據(DML語句)

針對表的數據進行操作,主要涉及4類:

  • 增加 insert
  • 刪除 delete
  • 修改 update
  • 查找 select

插入內容就相當於在表文件中按照MySQL的格式寫數據

3.7.1 insert語句

語法格式1:insert into table_name(col_name1,col_name2) values(value1,value2)
含義:

  • field和value是一一對應的。
  • 當字段名省略時,表示插入字段所有數據,values后面的值需要列出所有字段

語法格式2:insert into table_name(col_name) select field from table_name
含義:

  • 把select查到的結果,當作數據來賦值給value
  • 查詢到的數據字段要和插入的字段數量一致

語法格式3:insert into table_name (col_name,...) values (value1,..) on duplicate key update col_name=value1,...;

  • 如果主鍵沖突、唯一鍵沖突,就執行update后的語句,這條語句的意思是:主鍵不存在則新增記錄,主鍵存在,則更新部分字段。

語法格式4:insert ignore into table_name (col_name1,..) values (values1,..);

  • 如果主鍵沖突、唯一鍵沖突,就忽略錯誤,返回一個警告
  • 一般用在大批量導入測試數據的場景下
INSERT INTO `test`.`employees_copy` (
	`id`,
	`emp_no`,
	`birth_date`,
	`first_name`,
	`last_name`,
	`gender`,
	`FK_depet_no`,
	`hire_date`
)
VALUES
	(
    '10',
    '10010',
    '1990-08-02',
    'Dahl',
    'Lee',
    'F',
    'd001',
    '1990-08-02'
);

INSERT INTO boy (id) SELECT
	id
FROM
	employees;

3.7.2 update 語句

語法格式:update [ignore] table_name set col_name = value1,... [ where xxx = xxx

  • 注意更新語句一定要帶where條件,除非你真的知道你要改什么東西
UPDATE student
SET NAME = 'dahl'
WHERE
	id = 2;

3.7.3 delete 語句

語法格式:delete from table_name [ where xxx = xxx ]

  • 刪除一定要包含條件
DELETE
FROM
	student
WHERE
	id = 2;

生產中不會真的刪除數據,一般都會添加標致位來區分是否刪除。除非你真的要刪除。

3.7.4 select 語句

select 語句是 SQL中最復雜的語句,因為它非常靈活。下面是select語句的完整格式

SELECT
	[ DISTINCT ] select_expr ,...
FROM
	table_references 
WHERE
	where_definition  
GROUP BY
	{ col_name | expr | position } [ ASC | DESC ],...[ WITH ROLLUP ]
HAVING
	where_definition 
ORDER BY
	{ col_name | expr | position } [ ASC | DESC ] ,...
LIMIT {[ OFFSET ,] row_count | row_count OFFSET OFFSET }
[ FOR UPDATE | LOCK IN SHARE MODE ]]

FOR UPDATE 會把行進行鎖定(排他鎖)

3.7.4.1 簡單查詢

使用select col_name,... from table_name;

select * from student;
select id,name from student;
select id as std_no,name from student;
select std.id ,std.name from student as std;
select id,CONCAT(first_name,last_name) as name  from student;

  • 當僅存在一個表時,select后面的字段可以不用跟表明。
  • as 語句表示別名,是可以省略的,但是建議不要省略別名。
  • * 表示所有字段。
  • concat:字符串處理函數,用於合並

3.7.4.2 limit子句

對結果集進行過濾,限制輸出的條目數

  • limit:限制輸出的條目數
  • offset:與limit連用,表示偏移量
select * from employees limit 3 -- 輸出3條信息
select * from employees limit 3 offset 10 -- 漂移10條以后再輸出3條
select * from employees limit 10,3 --漂移10條以后再輸出3條

注意:limt還支持: 偏移量,取幾條。其實就是簡寫而已。上面例子第二句和第三句的含義是相同的。

Limit 必須在排序之后,因為排序會改變limit顯示的記錄

3.7.4.3 where子句

where子句主要用於做條件判斷,它支持的操作符如下:

運算符 描述
= 等於
<> 不等於(!=也可以。只不過不太符合SQL的規范)
>、<、>=、<= 大於、小於、大於等於、小於等於
BETWEEN 在某個范圍之內,between a and b等價於[a, b]
LIKE 字符串模式匹配,%表示任意多個字符,_表示一個字符
IN 指定針對某個列的多個可能值
AND
OR
select first_name from employees where emp_no > 10;
select * from salaries where salary > 50000;
select * from salaries where salary between 60000 and 80000;  -- 60000 < salary < 80000
select * from employees where last_name like 'P%';
SELECT emp.emp_no AS no,CONCAT(first_name,' ', last_name) AS name from employees AS emp where emp.emp_no in (10009,100010,10020); -- 類似集合類型

關於使用like進行模糊匹配:

  • 建議使用左前綴,因為效率高。('%a%',和'%a'效率很低,建議不要使用,除非真的需要)
  • 能不用like,就不用,效率很低,如果真的要搜索,那么建議使用搜索引擎(solr、lucence、elasticsearch)

3.7.4.4 order by子句

對查詢結果進行排序,可以升序ASC、降序DESC

select * from salaries order by salary limit 3
select * from salaries order by salary desc;
select * from salaries ORDER by emp_no desc,salary desc

默認為升序,當指定多個列時,優先按照第一列排序、當第一列相同時,再使用第二列排序。

3.7.4.5 distinct 去重

distinct 用於對字段進行去重操作,相同的只取1個

select distinct emp_no from salaries;
select distinct emp_no,salary from salaries;
  • 當distinct包含連個字段時,那么就是聯合去重了。即以(emp_np,salay)為整體進行去重

3.7.4.6 聚合函數

常用的聚合函數如下表:

函數 描述
COUNT(expr) 返回記錄中記錄的數目,如果指定列,則返回非NULL值的行數
COUNT(DISTINCT expr,[expr...])
AVG([DISTINCT] expr)
MIN(expr), MAX(expr)
SUM([DISTINCT] expr)

看需求,count一般會和分組進行連用,也常用在統計條數,count(id),在統計條數時,建議使用主鍵字段,可以獲得更快的統計速度。

3.7.4.7 group by和having

group by主要用於分組顯示,如果想要對分組后的數據進行再次過濾,可以使用having子句。

select emp_no,sum(salary) as sum_sal from salaries group by emp_no having sum_sal > 1000000;
  • group by 跟多個字段時,可以理解為 將多個字段組合成元組來分組,當元組唯一時,進行聚合統計。
  • 除分組和聚合字段以外的其他字段(非分組字段),是不可預知的。
  • 對分組之后的數據再次過濾,就需要使用Having了。可以對聚合后的結果設置別名來在having中引用。

3.7.4.8 子查詢

查詢語句可以嵌套,內部查詢就是子查詢。

  • 子查詢必須在一組小括號中。
  • 子查詢中不能使用Order by。
select f.salary from (select * from salaries where salaries.emp_no > 10003) as f
select first_name from employees where emp_no in (select emp_no from salaries);

3.7.4.9 inner join(內連接)

inner join,簡寫為join ,用於連接兩個表的內容,需要注意的是,連接方式為笛卡爾乘積,全部交叉。

  • A表有20條數據,B表有20條數據的話,那么a join b 就是 400條數據。
  • 當B表存在於A表同名的數據時,會被重命名

有以下兩種方式:

  • 等值連接:只選某些field相等的元組(行),使用on限定關聯的結果
  • 自然連接(natural join):特殊的等值連接,會去掉重復的列。用的很少(一般僅僅會留下兩表中主鍵相同的記錄)
select * from employees natural join salaries;
select * from employees inner join salaries on employees.emp_no = salaries.emp_no

3.7.4.10 outer join(外連接)

outer join 外連接,主要分為:

  • 左外連接(left join):從左表(table1)返回所有的行,即使右表(table2)中沒有匹配。如果右表中沒有匹配,則結果為 NULL。
  • 右外連接(right join):從右表(table2)返回所有的行,即使左表(table1)中沒有匹配。如果左表中沒有匹配,則結果為 NULL

在mariadb中,outer join 必須要配合on參數使用,否則會提示語法錯誤

select * from	employees left join salaries on employees.emp_no = salaries.emp_no where employees.emp_no > 10010;

在使用left jion時,on和where條件的區別如下:

  1. on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
  2. where條件是在臨時表生成好后,再對臨時表進行過濾的條件。

自己和自己連接

給定 Employee 表,編寫一個 SQL 查詢,該查詢可以獲取收入超過他們經理的員工的姓名。在上面的表格中,Joe 是唯一一個收入超過他的經理的員工

表結構:

Create table If Not Exists Employee (Id int, Name varchar(255), Salary int, ManagerId int)
Truncate table Employee
insert into Employee (Id, Name, Salary, ManagerId) values ('1', 'Joe', '70000', '3')
insert into Employee (Id, Name, Salary, ManagerId) values ('2', 'Henry', '80000', '4')
insert into Employee (Id, Name, Salary, ManagerId) values ('3', 'Sam', '60000', 'None')
insert into Employee (Id, Name, Salary, ManagerId) values ('4', 'Max', '90000', 'None')

sql語句:

select emp.Name as Employee from Employee  as emp left join Employee as man_emp on emp.ManagerID = man_emp.Id where emp.Salary > man_emp.Salary;

4 儲過程、觸發器

  • 存儲過程(Stored Procedure):數據庫系統中,一段完成特定功能的SQL語句。編寫成類似函數的方式,可以傳參並調用。支持流程控制語句。
  • 觸發器(Trigger):由事件觸發的特殊的存儲過程,例如insert數據時觸發。

這兩種技術,雖然是數據庫高級內容,性能不錯,但基本很少用了。它們移植性差,使用時占用的服務器資源,排錯、維護不方便。

最大的原因,不太建議把邏輯放在數據庫中。

5 事務Transaction

InnoDB引擎,支持事務。
事務,由若干條語句組成的,指的是要做的一系列操作。
關系型數據庫中支持事務,必須支持其四個屬性(ACID):

特性 描述
原子性(atomicity) 一個事務是一個不可分割的工作單位,事務中包括的所有操作要么全部做完,要么什么都不做
一致性(consistency) 事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的
隔離性(isolation) 一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對並發的其他事務是隔離的,並發執行的各個事務之間不能互相干擾
持久性(durability) 持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響

分析:

  • 原子性:要求事務中的所有操作,不可分割,不能做了一部分操作,還剩一部分操作;
  • 一致性:多個事務並行執行的結果,應該和事務排隊執行的結果一致。如果事務的並行執行和多線程讀寫共享資源一樣不可預期,就不能保證一致性。
  • 隔離性:就是指多個事務訪問共同的數據了,應該互不干擾。隔離性,指的是究竟在一個事務處理期間,其他事務能不能訪問的問題
  • 持久性:比較好理解,就是事務提交后,數據不能丟失。

6 MySQL隔離級別

隔離性不好,事務的操作就會互相影響,帶來不同嚴重程度的后果。

6.1 隔離性不好,帶來的問題

  1. 更新丟失Lost Update:事務A和B,更新同一個數據,它們都讀取了初始值100,A要減10,B要加100,A減去10后更新為90,B加100更新為200,A的更新丟失了,就像從來沒有減過10一樣。
  2. 臟讀:事務A和B,事務B讀取到了事務A未提交的數據(這個數據可能是一個中間值,也可能事務A后來回滾事務)。事務A是否最后提交並不關心。只要讀取到了這個被修改的數據就是臟讀。
  3. 不可重復讀Unrepeatable read:事務A在事務執行中相同查詢語句,得到了不同的結果,不能保證同一條查詢語句重復讀相同的結果就是不可
    以重復讀。
    • 例如,事務A查詢了一次后,事務B修改了數據,事務A又查詢了一次,發現數據不一致了。
    • 注意,臟讀講的是可以讀到相同的數據的,但是讀取的是一個未提交的數據,而不是提交的最終結果。
  4. 幻讀Phantom read:事務A中同一個查詢要進行多次,事務B插入數據,導致A返回不同的結果集,如同幻覺,就是幻讀。數據集有記錄增加了,可以看做是增加了記錄的不可重復讀。

6.2 隔離級別

隔離級別由低到高,如下表

隔離級別 描述
READ UNCOMMITTED 讀取到未提交的數據
READ COMMITTED 讀已經提交的數據,ORACLE默認隔離級別
REPEATABLE READ 可以重復讀,MySQL的 默認隔離級別。
SERIALIZABLE 可串行化。事務間完全隔離,事務不能並發,只能串行執行
  • 隔離級別越高,串行化越高,數據庫執行效率低;隔離級別越低,並行度越高,性能越高。
  • 隔離級別越高,當前事務處理的中間結果對其它事務不可見程度越高。
-- 設置會話級或者全局隔離級別
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
{READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
-- 查詢隔離級別
SELECT @@global.tx_isolation;
SELECT @@tx_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 禁用自動提交
SET AUTOCOMMIT = 0

小結:

  • SERIALIZABLE,串行了,解決所有問題
  • REPEATABLE READ,事務A中同一條查詢語句返回同樣的結果,就是可以重復讀數據了。例如語句為(select *from user)。解決的辦法有:
    1. 對select的數據加鎖,不允許其它事務刪除、修改的操作
    2. 第一次select的時候,對最后一次確切提交的事務的結果做快照
    3. 解決了不可以重復讀,但是有可能出現幻讀。因為另一個事務可以增刪數據。
  • READ COMMITTED,在事務中,每次select可以讀取到別的事務剛提交成功的新的數據。因為讀到的是提交后的數據,解決了臟讀,但是不能解決 不可重復讀 和 幻讀 的問題。因為其他事務前后修改了數據或增刪了數據。
  • READ UNCOMMITTED,能讀取到別的事務還沒有提交的數據,完全沒有隔離性可言,出現了臟讀,當前其他問題都可能出現。

6.3 事務語法

START TRANSACTION或BEGIN開始一個事務,START TRANSACTION是標准SQL的語法。
使用COMMIT提交事務后,變更成為永久變更。
ROLLBACK可以在提交事務之前,回滾變更,事務中的操作就如同沒有發生過一樣(原子性)。
SET AUTOCOMMIT語句可以禁用或啟用默認的autocommit模式,用於當前連接。SET AUTOCOMMIT = 0禁用自
動提交事務。如果開啟自動提交,如果有一個修改表的語句執行后,會立即把更新存儲到磁盤。

6.4 數據倉庫和數據庫的區別

本質上來說沒有區別,都是存放數據的地方。但是

  • 數據庫關注數據的持久化、數據的關系,為業務系統提供支持,事務支持;
  • 數據倉庫存儲數據的是為了分析或者發掘而設計的表結構,可以存儲海量數據。

數據庫存儲在線交易數據OLTP(聯機事務處理OLTP,On-line Transaction Processing);數據倉庫存儲歷史數據用於分析OLAP(聯機分析處理OLAP,On-Line Analytical Processing)。數據庫支持在線業務,需要頻繁增刪改查;數據倉庫一般囤積歷史數據支持用於分析的SQL,一般不建議刪改。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM