天天看點

咱也搞個半小時搞定mysql(基于9000小時定理+概念化學習的現實應用)

常見很多十天,二十天學會什麼東東,當然但多數聲音都是吐槽,其實,仔細想想,如果基本掌握一門計算機技能,十天半個月是很正常的,我們簡單分析分析。

一:技能分級

我們簡單做個技能分級,就簡單的分三個層次吧,想明白了對我們的學習多少會有幫助。

第一層:掌握技能的基礎應用,比如程式設計語言,這個層次就是對某一門程式設計語言的常用關鍵字,常用程式設計邏輯,常見的程式組織方式,常用的算法思維等(就還是簡單的按二八定理看,其實對于一門技術,常用的關鍵技術點可能隻占該技術總技術點的20%)。

第二層:了解技能的工作原理。比如Java,那麼就要很好的了解JVM的工作機制等

第三層:了解技能的設計原因。同樣比如Java,要了解JVM的很多機制為什麼采用現行方案,而不是用别的方案,比如spark,為什麼scala應用比python更合理等等。

二:9000小時定理

大家應該都聽說過偉大的一萬小時定理,但是,有一點很重要,就是對于領域想去不是很遠的方向,這一萬小時定理中有9000小時的積累是公用基礎;怎麼說呢:比如前兩年大火的機器學習,對于很多對計算機工程技術和算法有較深研究的人,很容易轉行到深度學習領域(工程應用而不是學術研究),因為他們在之前計算機工程方面積累的10000小時中有9000小時對轉行深度學習是公用的知識和認知基礎,他們隻需要再積累1000小時,也就不到半年的時間就可以足夠能力解決深度學習領域的問題。

三:概念化學習

對于一門技術的學習,主要是對該技能關鍵知識點的了解和認知深度的進階。比如學習一門程式設計語言,程式可以了解成兩部分:一部分是程式員命名的字元,是程式員了解的部分;還有一部分是程式設計語言關鍵字,計算機認識的部分。程式的執行就是計算機通過關鍵字的設定和語言規範的設定,按照程式員的思路來工作。

是以,如果工作中需要快速掌握一門技術,可以考慮從兩方面着手:

  1. 快速掌握常用關鍵技術點
  2. 定位問題,尋找相對成熟的解決方案。

    程式員的定位不應該是寫代碼,而是定位問題,找合适的工具解決問題。

說正事,十多分鐘搞定MySQL

大多數計算機問題可以了解成IO問題,同樣,所有資料庫的操作可以抽象成:增,查,删,改,打。我們從這個角度聊聊:

1. 資料庫操作

-- 檢視目前資料庫
    SELECT DATABASE();
-- 顯示目前時間、使用者名、資料庫版本
    SELECT now(), user(), version();
-- 建立庫
    CREATE DATABASE[ IF NOT EXISTS] 資料庫名 資料庫選項
    資料庫選項:
        CHARACTER SET charset_name
        COLLATE collation_name
-- 檢視已有庫
    SHOW DATABASES[ LIKE 'PATTERN']
-- 檢視目前庫資訊
    SHOW CREATE DATABASE 資料庫名
-- 修改庫的選項資訊
    ALTER DATABASE 庫名 選項資訊
-- 删除庫
    DROP DATABASE[ IF EXISTS] 資料庫名
        同時删除該資料庫相關的目錄及其目錄内容           

2. 表的操作

-- 建立表
    CREATE [TEMPORARY] TABLE[ IF NOT EXISTS] [庫名.]表名 ( 表的結構定義 )[ 表選項]
        每個字段必須有資料類型
        最後一個字段後不能有逗号
        TEMPORARY 臨時表,會話結束時表自動消失
        對于字段的定義:
            字段名 資料類型 [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string']
-- 表選項
    -- 字元集
        CHARSET = charset_name
        如果表沒有設定,則使用資料庫字元集
    -- 存儲引擎
        ENGINE = engine_name
        表在管理資料時采用的不同的資料結構,結構不同會導緻處理方式、提供的特性操作等不同
        常見的引擎:InnoDB MyISAM Memory/Heap BDB Merge Example CSV MaxDB Archive
        不同的引擎在儲存表的結構和資料時采用不同的方式
        MyISAM表檔案含義:.frm表定義,.MYD表資料,.MYI表索引
        InnoDB表檔案含義:.frm表定義,表空間資料和日志檔案
        SHOW ENGINES -- 顯示存儲引擎的狀态資訊
        SHOW ENGINE 引擎名 {LOGS|STATUS} -- 顯示存儲引擎的日志或狀态資訊
    -- 自增起始數
        AUTO_INCREMENT = 行數
    -- 資料檔案目錄
        DATA DIRECTORY = '目錄'
    -- 索引檔案目錄
        INDEX DIRECTORY = '目錄'
    -- 表注釋
        COMMENT = 'string'
    -- 分區選項
        PARTITION BY ... (詳細見手冊)
-- 檢視所有表
    SHOW TABLES[ LIKE 'pattern']
    SHOW TABLES FROM 表名
-- 檢視表機構
    SHOW CREATE TABLE 表名 (資訊更詳細)
    DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN']
    SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
-- 修改表
    -- 修改表本身的選項
        ALTER TABLE 表名 表的選項
        eg: ALTER TABLE 表名 ENGINE=MYISAM;
    -- 對表進行重命名
        RENAME TABLE 原表名 TO 新表名
        RENAME TABLE 原表名 TO 庫名.表名 (可将表移動到另一個資料庫)
        -- RENAME可以交換兩個表名
    -- 修改表的字段機構(13.1.2. ALTER TABLE文法)
        ALTER TABLE 表名 操作名
        -- 操作名
            ADD[ COLUMN] 字段定義       -- 增加字段
                AFTER 字段名          -- 表示增加在該字段名後面
                FIRST               -- 表示增加在第一個
            ADD PRIMARY KEY(字段名)   -- 建立主鍵
            ADD UNIQUE [索引名](字段名)-- 建立唯一索引
            ADD INDEX [索引名](字段名) -- 建立普通索引
            DROP[ COLUMN] 字段名      -- 删除字段
            MODIFY[ COLUMN] 字段名 字段屬性     -- 支援對字段屬性進行修改,不能修改字段名(所有原有屬性也需寫上)
            CHANGE[ COLUMN] 原字段名 新字段名 字段屬性      -- 支援對字段名修改
            DROP PRIMARY KEY    -- 删除主鍵(删除主鍵前需删除其AUTO_INCREMENT屬性)
            DROP INDEX 索引名 -- 删除索引
            DROP FOREIGN KEY 外鍵    -- 删除外鍵
-- 删除表
    DROP TABLE[ IF EXISTS] 表名 ...
-- 清空表資料
    TRUNCATE [TABLE] 表名
-- 複制表結構
    CREATE TABLE 表名 LIKE 要複制的表名
-- 複制表結構和資料
    CREATE TABLE 表名 [AS] SELECT * FROM 要複制的表名
-- 檢查表是否有錯誤
    CHECK TABLE tbl_name [, tbl_name] ... [option] ...
-- 優化表
    OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
-- 修複表
    REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]
-- 分析表
    ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...           
  1. 資料操作
-- 增
    INSERT [INTO] 表名 [(字段清單)] VALUES (值清單)[, (值清單), ...]
        -- 如果要插入的值清單包含所有字段并且順序一緻,則可以省略字段清單。
        -- 可同時插入多條資料記錄!
        REPLACE 與 INSERT 完全一樣,可互換。
    INSERT [INTO] 表名 SET 字段名=值[, 字段名=值, ...]
-- 查
    SELECT 字段清單 FROM 表名[ 其他子句]
        -- 可來自多個表的多個字段
        -- 其他子句可以不使用
        -- 字段清單可以用*代替,表示所有字段
-- 删
    DELETE FROM 表名[ 删除條件子句]
        沒有條件子句,則會删除全部
-- 改
    UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新條件]           

4. 字元集編碼

-- MySQL、資料庫、表、字段均可設定編碼
-- 資料編碼與用戶端編碼不需一緻
SHOW VARIABLES LIKE 'character_set_%'   -- 檢視所有字元集編碼項
    character_set_client        用戶端向伺服器發送資料時使用的編碼
    character_set_results       伺服器端将結果傳回給用戶端所使用的編碼
    character_set_connection    連接配接層編碼
SET 變量名 = 變量值
    SET character_set_client = gbk;
    SET character_set_results = gbk;
    SET character_set_connection = gbk;
SET NAMES GBK;  -- 相當于完成以上三個設定
-- 校對集
    校對集用以排序
    SHOW CHARACTER SET [LIKE 'pattern']/SHOW CHARSET [LIKE 'pattern']   檢視所有字元集
    SHOW COLLATION [LIKE 'pattern']     檢視所有校對集
    CHARSET 字元集編碼     設定字元集編碼
    COLLATE 校對集編碼     設定校對集編碼           

5. 資料類型(列類型)

1. 數值類型
 a. 整型 
類型         位元組     範圍(有符号位)
tinyint     1位元組    -128 ~ 127      無符号位:0 ~ 255
smallint    2位元組    -32768 ~ 32767
mediumint   3位元組    -8388608 ~ 8388607
int         4位元組
    bigint      8位元組
    int(M)  M表示總位數
    - 預設存在符号位,unsigned 屬性修改
    - 顯示寬度,如果某個數不夠定義字段時設定的位數,則前面以0補填,zerofill 屬性修改
        例:int(5)   插入一個數'123',補填後為'00123'
    - 在滿足要求的情況下,越小越好。
    - 1表示bool值真,0表示bool值假。MySQL沒有布爾類型,通過整型0和1表示。常用tinyint(1)表示布爾型。

 b. 浮點型
    類型             位元組     範圍
    float(單精度)     4位元組
    double(雙精度)    8位元組
    浮點型既支援符号位 unsigned 屬性,也支援顯示寬度 zerofill 屬性。
 不同于整型,前後均會補填0.
    定義浮點型時,需指定總位數和小數位數。
        float(M, D)     double(M, D)
        M表示總位數,D表示小數位數。
        M和D的大小會決定浮點數的範圍。不同于整型的固定範圍。
        M既表示總位數(不包括小數點和正負号),也表示顯示寬度(所有顯示符号均包括)。
        支援科學計數法表示。
        浮點數表示近似值。

-- c. 定點數 ----------
    decimal -- 可變長度
    decimal(M, D)   M也表示總位數,D表示小數位數。
    儲存一個精确的數值,不會發生資料的改變,不同于浮點數的四舍五入。
    将浮點數轉換為字元串來儲存,每9位數字儲存為4個位元組。

2. 字元串類型

   a. char, varchar
    char    定長字元串,速度快,但浪費空間
    varchar 變長字元串,速度慢,但節省空間
    M表示能存儲的最大長度,此長度是字元數,非位元組數。
    不同的編碼,所占用的空間不同。
    char,最多255個字元,與編碼無關。
    varchar,最多65535字元,與編碼有關。
    一條有效記錄最大不能超過65535個位元組。
  utf8 最大為21844個字元,gbk 最大為32766個字元,latin1 最大為65532個字元
    varchar 是變長的,需要利用存儲空間儲存 varchar 的長度,如果資料小于255個位元組,則采用一個位元組來儲存長度,反之需要兩個位元組來儲存。
    varchar 的最大有效長度由最大行大小和使用的字元集确定。
    最大有效長度是65532位元組,因為在varchar存字元串時,第一個位元組是空的,不存在任何資料,然後還需兩個位元組來存放字元串的長度,是以有效長度是64432-1-2=65532位元組。
    例:若一個表定義為 CREATE TABLE tb(c1 int, c2 char(30), c3 varchar(N)) charset=utf8; 問N的最大值是多少? 答:(65535-1-2-4-30*3)/3

   b. blob, text  
    blob 二進制字元串(位元組字元串) tinyblob, blob, mediumblob, longblob
    text 非二進制字元串(字元字元串)
        tinytext, text, mediumtext, longtext
    text 在定義時,不需要定義長度,也不會計算總長度。
    text 類型在定義時,不可給default值

   c. binary, varbinary  
    類似于char和varchar,用于儲存二進制字元串,也就是儲存位元組字元串而非字元字元串。
    char, varchar, text 對應 binary, varbinary, blob.

3. 日期時間類型
    一般用整型儲存時間戳,因為PHP可以很友善的将時間戳進行格式化。
    datetime    8位元組    日期及時間     1000-01-01 00:00:00 到 9999-12-31 23:59:59
    date        3位元組    日期         1000-01-01 到 9999-12-31
    timestamp   4位元組    時間戳        19700101000000 到 2038-01-19 03:14:07
    time        3位元組    時間         -838:59:59 到 838:59:59
    year        1位元組    年份         1901 - 2155
datetime    YYYY-MM-DD hh:mm:ss
timestamp   YY-MM-DD hh:mm:ss
            YYYYMMDDhhmmss
            YYMMDDhhmmss
            YYYYMMDDhhmmss
            YYMMDDhhmmss
date        YYYY-MM-DD
            YY-MM-DD
            YYYYMMDD
            YYMMDD
            YYYYMMDD
            YYMMDD
time        hh:mm:ss
            hhmmss
            hhmmss
year        YYYY
            YY
            YYYY
            YY

4. 枚舉和集合

-- 枚舉(enum) ----------
enum(val1, val2, val3...)
    在已知的值中進行單選。最大數量為65535.
    枚舉值在儲存時,以2個位元組的整型(smallint)儲存。每個枚舉值,按儲存的位置順序,從1開始逐一遞增。
    表現為字元串類型,存儲卻是整型。
    NULL值的索引是NULL。
    空字元串錯誤值的索引值是0。


-- 集合(set) ----------
set(val1, val2, val3...)
    create table tab ( gender set('男', '女', '無') );
    insert into tab values ('男, 女');
    最多可以有64個不同的成員。以bigint存儲,共8個位元組。采取位運算的形式。
    當建立表時,SET成員值的尾部空格将自動被删除。           

6. 列屬性(列限制)

1. PRIMARY 主鍵
    - 能唯一辨別記錄的字段,可以作為主鍵。
    - 一個表隻能有一個主鍵。
    - 主鍵具有唯一性。
    - 聲明字段時,用 primary key 辨別。
        也可以在字段清單之後聲明
            例:create table tab ( id int, stu varchar(10), primary key (id));
    - 主鍵字段的值不能為null。
    - 主鍵可以由多個字段共同組成。此時需要在字段清單後聲明的方法。
        例:create table tab ( id int, stu varchar(10), age int, primary key (stu, age));
2. UNIQUE 唯一索引(唯一限制)
    使得某字段的值也不能重複。
3. NULL 限制
    null不是資料類型,是列的一個屬性。
    表示目前列是否可以為null,表示什麼都沒有。
    null, 允許為空。預設。
    not null, 不允許為空。
    insert into tab values (null, 'val');
        -- 此時表示将第一個字段的值設為null, 取決于該字段是否允許為null
4. DEFAULT 預設值屬性
    目前字段的預設值。
    insert into tab values (default, 'val');    -- 此時表示強制使用預設值。
    create table tab ( add_time timestamp default current_timestamp );
        -- 表示将目前時間的時間戳設為預設值。
        current_date, current_time
5. AUTO_INCREMENT 自動增長限制
    自動增長必須為索引(主鍵或unique)
    隻能存在一個字段為自動增長。
    預設為1開始自動增長。可以通過表屬性 auto_increment = x進行設定,或 alter table tbl auto_increment = x;
6. COMMENT 注釋
    例:create table tab ( id int ) comment '注釋内容';
7. FOREIGN KEY 外鍵限制
    用于限制主表與從表資料完整性。
    alter table t1 add constraint `t1_t2_fk` foreign key (t1_id) references t2(id);
        -- 将表t1的t1_id外鍵關聯到表t2的id字段。
        -- 每個外鍵都有一個名字,可以通過 constraint 指定
    存在外鍵的表,稱之為從表(子表),外鍵指向的表,稱之為主表(父表)。
    作用:保持資料一緻性,完整性,主要目的是控制存儲在外鍵表(從表)中的資料。
    MySQL中,可以對InnoDB引擎使用外鍵限制:
    文法:
    foreign key (外鍵字段) references 主表名 (關聯字段) [主表記錄删除時的動作] [主表記錄更新時的動作]
    此時需要檢測一個從表的外鍵需要限制為主表的已存在的值。外鍵在沒有關聯的情況下,可以設定為null.前提是該外鍵列,沒有not null。
    可以不指定主表記錄更改或更新時的動作,那麼此時主表的操作被拒絕。
    如果指定了 on update 或 on delete:在删除或更新時,有如下幾個操作可以選擇:
    1. cascade,級聯操作。主表資料被更新(主鍵值更新),從表也被更新(外鍵值更新)。主表記錄被删除,從表相關記錄也被删除。
    2. set null,設定為null。主表資料被更新(主鍵值更新),從表的外鍵被設定為null。主表記錄被删除,從表相關記錄外鍵被設定成null。但注意,要求該外鍵列,沒有not null屬性限制。
    3. restrict,拒絕父表删除和更新。
    注意,外鍵隻被InnoDB存儲引擎所支援。其他引擎是不支援的。           

7. 建表規範

-- Normal Format, NF
        - 每個表儲存一個實體資訊
        - 每個具有一個ID字段作為主鍵
        - ID主鍵 + 原子表
    -- 1NF, 第一範式
        字段不能再分,就滿足第一範式。
    -- 2NF, 第二範式
        滿足第一範式的前提下,不能出現部分依賴。
        消除符合主鍵就可以避免部分依賴。增加單列關鍵字。
    -- 3NF, 第三範式
        滿足第二範式的前提下,不能出現傳遞依賴。
        某個字段依賴于主鍵,而有其他字段依賴于該字段。這就是傳遞依賴。
        将一個實體資訊的資料放在一個表内實作。           

8.1 SELECT操作

SELECT [ALL|DISTINCT] select_expr FROM -> WHERE -> GROUP BY [合計函數] -> HAVING -> ORDER BY -> LIMIT
a. select_expr
    -- 可以用 * 表示所有字段。
        select * from tb;
    -- 可以使用表達式(計算公式、函數調用、字段也是個表達式)
        select stu, 29+25, now() from tb;
    -- 可以為每個列使用别名。适用于簡化列辨別,避免多個列辨別符重複。
        - 使用 as 關鍵字,也可省略 as.
        select stu+10 as add10 from tb;
b. FROM 子句
    用于辨別查詢來源。
    -- 可以為表起别名。使用as關鍵字。
        SELECT * FROM tb1 AS tt, tb2 AS bb;
    -- from子句後,可以同時出現多個表。
        -- 多個表會橫向疊加到一起,而資料會形成一個笛卡爾積。
        SELECT * FROM tb1, tb2;
    -- 向優化符提示如何選擇索引
        USE INDEX、IGNORE INDEX、FORCE INDEX
        SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3;
        SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;
c. WHERE 子句
    -- 從from獲得的資料源中進行篩選。
    -- 整型1表示真,0表示假。
    -- 表達式由運算符和運算數組成。
        -- 運算數:變量(字段)、值、函數傳回值
        -- 運算符:
            =, <=>, <>, !=, <=, <, >=, >, !, &&, ||,
            in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor
            is/is not 加上ture/false/unknown,檢驗某個值的真假
            <=>與<>功能相同,<=>可用于null比較
d. GROUP BY 子句, 分組子句
    GROUP BY 字段/别名 [排序方式]
    分組後會進行排序。升序:ASC,降序:DESC
    以下[合計函數]需配合 GROUP BY 使用:
    count 傳回不同的非NULL值數目  count(*)、count(字段)
    sum 求和
    max 求最大值
    min 求最小值
    avg 求平均值
    group_concat 傳回帶有來自一個組的連接配接的非NULL值的字元串結果。組内字元串連接配接。
e. HAVING 子句,條件子句
    與 where 功能、用法相同,執行時機不同。
    where 在開始時執行檢測資料,對原資料進行過濾。
    having 對篩選出的結果再次進行過濾。
    having 字段必須是查詢出來的,where 字段必須是資料表存在的。
    where 不可以使用字段的别名,having 可以。因為執行WHERE代碼時,可能尚未确定列值。
    where 不可以使用合計函數。一般需用合計函數才會用 having
    SQL标準要求HAVING必須引用GROUP BY子句中的列或用于合計函數中的列。
f. ORDER BY 子句,排序子句
    order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...
    升序:ASC,降序:DESC
    支援多個字段的排序。
g. LIMIT 子句,限制結果數量子句
    僅對處理好的結果進行數量限制。将處理好的結果的看作是一個集合,按照記錄出現的順序,索引從0開始。
    limit 起始位置, 擷取條數
    省略第一個參數,表示從索引0開始。limit 擷取條數
h. DISTINCT, ALL 選項
    distinct 去除重複記錄
    預設為 all, 全部記錄           

8.2 UNION.

将多個select查詢的結果組合成一個結果集合。
    SELECT ... UNION [ALL|DISTINCT] SELECT ...
    預設 DISTINCT 方式,即所有傳回的行都是唯一的
    建議,對每個SELECT查詢加上小括号包裹。
    ORDER BY 排序時,需加上 LIMIT 進行結合。
    需要各select查詢的字段數量一樣。
    每個select查詢的字段清單(數量、類型)應一緻,因為結果中的字段名以第一條select語句為準。           

8.3 子查詢

- 子查詢需用括号包裹。
-- from型
    from後要求是一個表,必須給子查詢結果取個别名。
    - 簡化每個查詢内的條件。
    - from型需将結果生成一個臨時表格,可用以原表的鎖定的釋放。
    - 子查詢傳回一個表,表型子查詢。
    select * from (select * from tb where id>0) as subfrom where id>1;
-- where型
    - 子查詢傳回一個值,标量子查詢。
    - 不需要給子查詢取别名。
    - where子查詢内的表,不能直接用以更新。
    select * from tb where money = (select max(money) from tb);
    -- 列子查詢
        如果子查詢結果傳回的是一列。
        使用 in 或 not in 完成查詢
        exists 和 not exists 條件
            如果子查詢傳回資料,則傳回1或0。常用于判斷條件。
            select column1 from t1 where exists (select * from t2);
    -- 行子查詢
        查詢條件是一個行。
        select * from t1 where (id, gender) in (select id, gender from t2);
        行構造符:(col1, col2, ...) 或 ROW(col1, col2, ...)
        行構造符通常用于與對能傳回兩個或兩個以上列的子查詢進行比較。
    -- 特殊運算符
    != all()    相當于 not in
    = some()    相當于 in。any 是 some 的别名
    != some()   不等同于 not in,不等于其中某一個。
    all, some 可以配合其他運算符一起使用。           

8.4 連接配接查詢(join)

将多個表的字段進行連接配接,可以指定連接配接條件。
-- 内連接配接(inner join)
    - 預設就是内連接配接,可省略inner。
    - 隻有資料存在時才能發送連接配接。即連接配接結果不能出現空行。
    on 表示連接配接條件。其條件表達式與where類似。也可以省略條件(表示條件永遠為真)
    也可用where表示連接配接條件。
    還有 using, 但需字段名相同。 using(字段名)
    -- 交叉連接配接 cross join
        即,沒有條件的内連接配接。
        select * from tb1 cross join tb2;
-- 外連接配接(outer join)
    - 如果資料不存在,也會出現在連接配接結果中。
    -- 左外連接配接 left join
        如果資料不存在,左表記錄會出現,而右表為null填充
    -- 右外連接配接 right join
        如果資料不存在,右表記錄會出現,而左表為null填充
-- 自然連接配接(natural join)
    自動判斷連接配接條件完成連接配接。
    相當于省略了using,會自動查找相同字段名。
    natural join
    natural left join
    natural right join
    
select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;           

8.5 導出

select * into outfile 檔案位址 [控制格式] from 表名;   -- 導出表資料

load data [local] infile 檔案位址 [replace|ignore] into table 表名 [控制格式]; -- 導入資料
    生成的資料預設的分隔符是制表符
    local未指定,則資料檔案必須在伺服器上
    replace 和 ignore 關鍵詞控制對現有的唯一鍵記錄的重複的處理
-- 控制格式
fields  控制字段格式
預設:fields terminated by '\t' enclosed by '' escaped by '\\'
    terminated by 'string'  -- 終止
    enclosed by 'char'      -- 包裹
    escaped by 'char'       -- 轉義
    -- 示例:
        SELECT a,b,a+b INTO OUTFILE '/tmp/result.text'
        FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
        LINES TERMINATED BY '\n'
        FROM test_table;
lines   控制行格式
預設:lines terminated by '\n'
    terminated by 'string'  -- 終止           

8.6 INSERT

select語句獲得的資料可以用insert插入。
可以省略對列的指定,要求 values () 括号内,提供給了按照列順序出現的所有字段的值。
    或者使用set文法。
    INSERT INTO tbl_name SET field=value,...;
可以一次性使用多個值,采用(), (), ();的形式。
    INSERT INTO tbl_name VALUES (), (), ();
可以在列值指定時,使用表達式。
    INSERT INTO tbl_name VALUES (field_value, 10+10, now());
可以使用一個特殊值 DEFAULT,表示該列使用預設值。
    INSERT INTO tbl_name VALUES (field_value, DEFAULT);
可以通過一個查詢的結果,作為需要插入的值。
    INSERT INTO tbl_name SELECT ...;
可以指定在插入的值出現主鍵(或唯一索引)沖突時,更新其他非主鍵列的資訊。
    INSERT INTO tbl_name VALUES/SET/SELECT ON DUPLICATE KEY UPDATE 字段=值, …;           

8.7 DELETE

DELETE FROM tbl_name [WHERE where_definition] [ORDER BY ...] [LIMIT row_count]
按照條件删除。where
指定删除的最多記錄數。limit
可以通過排序條件删除。order by + limit
支援多表删除,使用類似連接配接文法。
delete from 需要删除資料多表1,表2 using 表連接配接操作 條件。           

8.8 TRUNCATE

TRUNCATE [TABLE] tbl_name
清空資料
删除重建表
差別:
1,truncate 是删除表再建立,delete 是逐條删除
2,truncate 重置auto_increment的值。而delete不會
3,truncate 不知道删除了幾條,而delete知道。
4,當被用于帶分區的表時,truncate 會保留分區           

8.9 資料備份與還原

備份,将資料的結構與表内資料儲存起來。
利用 mysqldump 指令完成。
-- 導出
mysqldump [options] db_name [tables]
mysqldump [options] ---database DB1 [DB2 DB3...]
mysqldump [options] --all--database
1. 導出一張表
  mysqldump -u使用者名 -p密碼 庫名 表名 > 檔案名(D:/a.sql)
2. 導出多張表
  mysqldump -u使用者名 -p密碼 庫名 表1 表2 表3 > 檔案名(D:/a.sql)
3. 導出所有表
  mysqldump -u使用者名 -p密碼 庫名 > 檔案名(D:/a.sql)
4. 導出一個庫
  mysqldump -u使用者名 -p密碼 --lock-all-tables --database 庫名 > 檔案名(D:/a.sql)
可以-w攜帶WHERE條件
-- 導入
1. 在登入mysql的情況下:
  source  備份檔案
2. 在不登入的情況下
  mysql -u使用者名 -p密碼 庫名 < 備份檔案           

8.10 試圖

視圖是一個虛拟表,其内容由查詢定義。同真實的表一樣,視圖包含一系列帶有名稱的列和行資料。但是,視圖并不在資料庫中以存儲的資料值集形式存在。行和列資料來自由定義視圖的查詢所引用的表,并且在引用視圖時動态生成。
    視圖具有表結構檔案,但不存在資料檔案。
    對其中所引用的基礎表來說,視圖的作用類似于篩選。定義視圖的篩選可以來自目前或其它資料庫的一個或多個表,或者其它視圖。通過視圖進行查詢沒有任何限制,通過它們進行資料修改時的限制也很少。
    視圖是存儲在資料庫中的查詢的sql語句,它主要出于兩種原因:安全原因,視圖可以隐藏一些資料,如:社會保險基金表,可以用視圖隻顯示姓名,位址,而不顯示社會保險号和工資數等,另一原因是可使複雜的查詢易于了解和使用。
-- 建立視圖
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement
    - 視圖名必須唯一,同時不能與表重名。
    - 視圖可以使用select語句查詢到的列名,也可以自己指定相應的列名。
    - 可以指定視圖執行的算法,通過ALGORITHM指定。
    - column_list如果存在,則數目必須等于SELECT語句檢索的列數
-- 檢視結構
    SHOW CREATE VIEW view_name
-- 删除視圖
    - 删除視圖後,資料依然存在。
    - 可同時删除多個視圖。
    DROP VIEW [IF EXISTS] view_name ...
-- 修改視圖結構
    - 一般不修改視圖,因為不是所有的更新視圖都會映射到表上。
    ALTER VIEW view_name [(column_list)] AS select_statement
-- 視圖作用
    1. 簡化業務邏輯
    2. 對用戶端隐藏真實的表結構
-- 視圖算法(ALGORITHM)
    MERGE       合并
        将視圖的查詢語句,與外部查詢需要先合并再執行!
    TEMPTABLE   臨時表
        将視圖執行完畢後,形成臨時表,再做外層查詢!
    UNDEFINED   未定義(預設),指的是MySQL自主去選擇相應的算法。           

8.11 事務(transaction)

事務是指邏輯上的一組操作,組成這組操作的各個單元,要不全成功要不全失敗。
    - 支援連續SQL的集體成功或集體撤銷。
    - 事務是資料庫在資料晚自習方面的一個功能。
    - 需要利用 InnoDB 或 BDB 存儲引擎,對自動送出的特性支援完成。
    - InnoDB被稱為事務安全型引擎。
-- 事務開啟
    START TRANSACTION; 或者 BEGIN;
    開啟事務後,所有被執行的SQL語句均被認作目前事務内的SQL語句。
-- 事務送出
    COMMIT;
-- 事務復原
    ROLLBACK;
    如果部分操作發生問題,映射到事務開啟前。
-- 事務的特性
    1. 原子性(Atomicity)
        事務是一個不可分割的工作機關,事務中的操作要麼都發生,要麼都不發生。
    2. 一緻性(Consistency)
        事務前後資料的完整性必須保持一緻。
        - 事務開始和結束時,外部資料一緻
        - 在整個事務過程中,操作是連續的
    3. 隔離性(Isolation)
        多個使用者并發通路資料庫時,一個使用者的事務不能被其它使用者的事物所幹擾,多個并發事務之間的資料要互相隔離。
    4. 持久性(Durability)
        一個事務一旦被送出,它對資料庫中的資料改變就是永久性的。
-- 事務的實作
    1. 要求是事務支援的表類型
    2. 執行一組相關的操作前開啟事務
    3. 整組操作完成後,都成功,則送出;如果存在失敗,選擇復原,則會回到事務開始的備份點。
-- 事務的原理
    利用InnoDB的自動送出(autocommit)特性完成。
    普通的MySQL執行語句後,目前的資料送出操作均可被其他用戶端可見。
    而事務是暫時關閉“自動送出”機制,需要commit送出持久化資料操作。
-- 注意
    1. 資料定義語言(DDL)語句不能被復原,比如建立或取消資料庫的語句,和建立、取消或更改表或存儲的子程式的語句。
    2. 事務不能被嵌套
-- 儲存點
    SAVEPOINT 儲存點名稱 -- 設定一個事務儲存點
    ROLLBACK TO SAVEPOINT 儲存點名稱 -- 復原到儲存點
    RELEASE SAVEPOINT 儲存點名稱 -- 删除儲存點
-- InnoDB自動送出特性設定
    SET autocommit = 0|1;   0表示關閉自動送出,1表示開啟自動送出。
    - 如果關閉了,那普通操作的結果對其他用戶端也不可見,需要commit送出後才能持久化資料操作。
    - 也可以關閉自動送出來開啟事務。但與START TRANSACTION不同的是,
        SET autocommit是永久改變伺服器的設定,直到下次再次修改該設定。(針對目前連接配接)
        而START TRANSACTION記錄開啟前的狀态,而一旦事務送出或復原後就需要再次開啟事務。(針對目前事務)           

8.12 鎖表

表鎖定隻用于防止其它用戶端進行不正當地讀取和寫入

MyISAM 支援表鎖,InnoDB 支援行鎖
-- 鎖定
    LOCK TABLES tbl_name [AS alias]
-- 解鎖
    UNLOCK TABLES
           

8.13 觸發器

觸發程式是與表有關的命名資料庫對象,當該表出現特定事件時,将激活該對象。    監聽:記錄的增加、修改、删除。
           
-- 建立觸發器
CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt
    參數:
    trigger_time是觸發程式的動作時間。它可以是 before 或 after,以指明觸發程式是在激活它的語句之前或之後觸發。
    trigger_event指明了激活觸發程式的語句的類型
        INSERT:将新行插入表時激活觸發程式
        UPDATE:更改某一行時激活觸發程式
        DELETE:從表中删除某一行時激活觸發程式
    tbl_name:監聽的表,必須是永久性的表,不能将觸發程式與TEMPORARY表或視圖關聯起來。
    trigger_stmt:當觸發程式激活時執行的語句。執行多個語句,可使用BEGIN...END複合語句結構
-- 删除
DROP TRIGGER [schema_name.]trigger_name
可以使用old和new代替舊的和新的資料
    更新操作,更新前是old,更新後是new.
    删除操作,隻有old.
    增加操作,隻有new.
-- 注意
    1. 對于具有相同觸發程式動作時間和事件的給定表,不能有兩個觸發程式。
           

8.14 字元操作

-- 字元連接配接函數
concat(str1,str2,...])
concat_ws(separator,str1,str2,...)

-- 分支語句
if 條件 then
    執行語句
elseif 條件 then
    執行語句
else
    執行語句
end if;

-- 修改最外層語句結束符
delimiter 自定義結束符号
    SQL語句
自定義結束符号
delimiter ;     -- 修改回原來的分号

-- 語句塊包裹
begin
    語句塊
end

-- 特殊的執行
1. 隻要添加記錄,就會觸發程式。
2. Insert into on duplicate key update 文法會觸發:
    如果沒有重複記錄,會觸發 before insert, after insert;
    如果有重複記錄并更新,會觸發 before insert, before update, after update;
    如果有重複記錄但是沒有發生更新,則觸發 before insert, before update
3. Replace 文法 如果有記錄,則執行 before insert, before delete, after delete, after insert           

8.15 SQL程式設計進階

--// 局部變量 ----------
-- 變量聲明
    declare var_name[,...] type [default value]
    這個語句被用來聲明局部變量。要給變量提供一個預設值,請包含一個default子句。值可以被指定為一個表達式,不需要為一個常數。如果沒有default子句,初始值為null。
-- 指派
    使用 set 和 select into 語句為變量指派。
    - 注意:在函數内是可以使用全局變量(使用者自定義的變量)


--// 全局變量 ----------
-- 定義、指派
set 語句可以定義并為變量指派。
set @var = value;
也可以使用select into語句為變量初始化并指派。這樣要求select語句隻能傳回一行,但是可以是多個字段,就意味着同時為多個變量進行指派,變量的數量需要與查詢的列數一緻。
還可以把指派語句看作一個表達式,通過select執行完成。此時為了避免=被當作關系運算符看待,使用:=代替。(set語句可以使用= 和 :=)。
select @var:=20;
select @v1:=id, @v2=name from t1 limit 1;
select * from tbl_name where @var:=30;
select into 可以将表中查詢獲得的資料賦給變量。
    -| select max(height) into @max_height from tb;
-- 自定義變量名
為了避免select語句中,使用者自定義的變量與系統辨別符(通常是字段名)沖突,使用者自定義變量在變量名前使用@作為開始符号。
@var=10;
    - 變量被定義後,在整個會話周期都有效(登入到退出)



--// 控制結構 ----------
-- if語句
if search_condition then
    statement_list   
[elseif search_condition then
    statement_list]
...
[else
    statement_list]
end if;
-- case語句
CASE value WHEN [compare-value] THEN result
[WHEN [compare-value] THEN result ...]
[ELSE result]
END
-- while循環
[begin_label:] while search_condition do
    statement_list
end while [end_label];
- 如果需要在循環内提前終止 while循環,則需要使用标簽;标簽需要成對出現。
    -- 退出循環
        退出整個循環 leave
        退出目前循環 iterate
        通過退出的标簽決定退出哪個循環



--// 内置函數 ----------
-- 數值函數
abs(x)          -- 絕對值 abs(-10.9) = 10
format(x, d)    -- 格式化千分位數值 format(1234567.456, 2) = 1,234,567.46
ceil(x)         -- 向上取整 ceil(10.1) = 11
floor(x)        -- 向下取整 floor (10.1) = 10
round(x)        -- 四舍五入去整
mod(m, n)       -- m%n m mod n 求餘 10%3=1
pi()            -- 獲得圓周率
pow(m, n)       -- m^n
sqrt(x)         -- 算術平方根
rand()          -- 随機數
truncate(x, d)  -- 截取d位小數
-- 時間日期函數
now(), current_timestamp();     -- 目前日期時間
current_date();                 -- 目前日期
current_time();                 -- 目前時間
date('yyyy-mm-dd hh:ii:ss');    -- 擷取日期部分
time('yyyy-mm-dd hh:ii:ss');    -- 擷取時間部分
date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); -- 格式化時間
unix_timestamp();               -- 獲得unix時間戳
from_unixtime();                -- 從時間戳獲得時間
-- 字元串函數
length(string)          -- string長度,位元組
char_length(string)     -- string的字元個數
substring(str, position [,length])      -- 從str的position開始,取length個字元
replace(str ,search_str ,replace_str)   -- 在str中用replace_str替換search_str
instr(string ,substring)    -- 傳回substring首次在string中出現的位置
concat(string [,...])   -- 連接配接字串
charset(str)            -- 傳回字串字元集
lcase(string)           -- 轉換成小寫
left(string, length)    -- 從string2中的左邊起取length個字元
load_file(file_name)    -- 從檔案讀取内容
locate(substring, string [,start_position]) -- 同instr,但可指定開始位置
lpad(string, length, pad)   -- 重複用pad加在string開頭,直到字串長度為length
ltrim(string)           -- 去除前端空格
repeat(string, count)   -- 重複count次
rpad(string, length, pad)   --在str後用pad補充,直到長度為length
rtrim(string)           -- 去除後端空格
strcmp(string1 ,string2)    -- 逐字元比較兩字串大小
-- 流程函數
case when [condition] then result [when [condition] then result ...] [else result] end   多分支
if(expr1,expr2,expr3)  雙分支。
-- 聚合函數
count()
sum();
max();
min();
avg();
group_concat()
-- 其他常用函數
md5();
default();

--// 存儲函數,自定義函數 ----------
-- 建立
    CREATE FUNCTION function_name (參數清單) RETURNS 傳回值類型
        函數體
    - 函數名,應該合法的辨別符,并且不應該與已有的關鍵字沖突。
    - 一個函數應該屬于某個資料庫,可以使用db_name.funciton_name的形式執行目前函數所屬資料庫,否則為目前資料庫。
    - 參數部分,由"參數名"和"參數類型"組成。多個參數用逗号隔開。
    - 函數體由多條可用的mysql語句,流程控制,變量聲明等語句構成。
    - 多條語句應該使用 begin...end 語句塊包含。
    - 一定要有 return 傳回值語句。
-- 删除
    DROP FUNCTION [IF EXISTS] function_name;
-- 檢視
    SHOW FUNCTION STATUS LIKE 'partten'
    SHOW CREATE FUNCTION function_name;
-- 修改
    ALTER FUNCTION function_name 函數選項

--// 存儲過程,自定義功能 ----------
-- 定義
存儲存儲過程 是一段代碼(過程),存儲在資料庫中的sql組成。
一個存儲過程通常用于完成一段業務邏輯,例如報名,交班費,訂單入庫等。
而一個函數通常專注與某個功能,視為其他程式服務的,需要在其他語句中調用函數才可以,而存儲過程不能被其他調用,是自己執行 通過call執行。
-- 建立
CREATE PROCEDURE sp_name (參數清單)
    過程體
參數清單:不同于函數的參數清單,需要指明參數類型
IN,表示輸入型
OUT,表示輸出型
INOUT,表示混合型
注意,沒有傳回值。


/* 存儲過程 */ ------------------
存儲過程是一段可執行性代碼的集合。相比函數,更偏向于業務邏輯。
調用:CALL 過程名
-- 注意
- 沒有傳回值。
- 隻能單獨調用,不可夾雜在其他語句中
-- 參數
IN|OUT|INOUT 參數名 資料類型
IN      輸入:在調用過程中,将資料輸入到過程體内部的參數
OUT     輸出:在調用過程中,将過程體處理完的結果傳回到用戶端
INOUT   輸入輸出:既可輸入,也可輸出
-- 文法
CREATE PROCEDURE 過程名 (參數清單)
BEGIN
    過程體
END           

8.16 使用者管理AND權限管理

-- root密碼重置
1. 停止MySQL服務
2.  [Linux] /usr/local/mysql/bin/safe_mysqld --skip-grant-tables &
    [Windows] mysqld --skip-grant-tables
3. use mysql;
4. UPDATE `user` SET PASSWORD=PASSWORD("密碼") WHERE `user` = "root";
5. FLUSH PRIVILEGES;
使用者資訊表:mysql.user
-- 重新整理權限
FLUSH PRIVILEGES;
-- 增加使用者
CREATE USER 使用者名 IDENTIFIED BY [PASSWORD] 密碼(字元串)
    - 必須擁有mysql資料庫的全局CREATE USER權限,或擁有INSERT權限。
    - 隻能建立使用者,不能賦予權限。
    - 使用者名,注意引号:如 'user_name'@'192.168.1.1'
    - 密碼也需引号,純數字密碼也要加引号
    - 要在純文字中指定密碼,需忽略PASSWORD關鍵詞。要把密碼指定為由PASSWORD()函數傳回的混編值,需包含關鍵字PASSWORD
-- 重命名使用者
RENAME USER old_user TO new_user
-- 設定密碼
SET PASSWORD = PASSWORD('密碼')  -- 為目前使用者設定密碼
SET PASSWORD FOR 使用者名 = PASSWORD('密碼') -- 為指定使用者設定密碼
-- 删除使用者
DROP USER 使用者名
-- 配置設定權限/添加使用者
GRANT 權限清單 ON 表名 TO 使用者名 [IDENTIFIED BY [PASSWORD] 'password']
    - all privileges 表示所有權限
    - *.* 表示所有庫的所有表
    - 庫名.表名 表示某庫下面的某表
    GRANT ALL PRIVILEGES ON `pms`.* TO 'pms'@'%' IDENTIFIED BY 'pms0817';
-- 檢視權限
SHOW GRANTS FOR 使用者名
    -- 檢視目前使用者權限
    SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();
-- 撤消權限
REVOKE 權限清單 ON 表名 FROM 使用者名
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 使用者名   -- 撤銷所有權限
-- 權限層級
-- 要使用GRANT或REVOKE,您必須擁有GRANT OPTION權限,并且您必須用于您正在授予或撤銷的權限。
全局層級:全局權限适用于一個給定伺服器中的所有資料庫,mysql.user
    GRANT ALL ON *.*和 REVOKE ALL ON *.*隻授予和撤銷全局權限。
資料庫層級:資料庫權限适用于一個給定資料庫中的所有目标,mysql.db, mysql.host
    GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*隻授予和撤銷資料庫權限。
表層級:表權限适用于一個給定表中的所有列,mysql.talbes_priv
    GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name隻授予和撤銷表權限。
列層級:列權限适用于一個給定表中的單一列,mysql.columns_priv
    當使用REVOKE時,您必須指定與被授權列相同的列。
-- 權限清單
ALL [PRIVILEGES]    -- 設定除GRANT OPTION之外的所有簡單權限
ALTER   -- 允許使用ALTER TABLE
ALTER ROUTINE   -- 更改或取消已存儲的子程式
CREATE  -- 允許使用CREATE TABLE
CREATE ROUTINE  -- 建立已存儲的子程式
CREATE TEMPORARY TABLES     -- 允許使用CREATE TEMPORARY TABLE
CREATE USER     -- 允許使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。
CREATE VIEW     -- 允許使用CREATE VIEW
DELETE  -- 允許使用DELETE
DROP    -- 允許使用DROP TABLE
EXECUTE     -- 允許使用者運作已存儲的子程式
FILE    -- 允許使用SELECT...INTO OUTFILE和LOAD DATA INFILE
INDEX   -- 允許使用CREATE INDEX和DROP INDEX
INSERT  -- 允許使用INSERT
LOCK TABLES     -- 允許對您擁有SELECT權限的表使用LOCK TABLES
PROCESS     -- 允許使用SHOW FULL PROCESSLIST
REFERENCES  -- 未被實施
RELOAD  -- 允許使用FLUSH
REPLICATION CLIENT  -- 允許使用者詢問從屬伺服器或主伺服器的位址
REPLICATION SLAVE   -- 用于複制型從屬伺服器(從主伺服器中讀取二進制日志事件)
SELECT  -- 允許使用SELECT
SHOW DATABASES  -- 顯示所有資料庫
SHOW VIEW   -- 允許使用SHOW CREATE VIEW
SHUTDOWN    -- 允許使用mysqladmin shutdown
SUPER   -- 允許使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL語句,mysqladmin debug指令;允許您連接配接(一次),即使已達到max_connections。
UPDATE  -- 允許使用UPDATE
USAGE   -- “無權限”的同義詞
GRANT OPTION    -- 允許授予權限           

8.17 維護資料庫

-- 分析和存儲表的關鍵字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 檢查一個或多個表是否有錯誤
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理資料檔案的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...           

8.18 其他

1. 可用反引号(`)為辨別符(庫名、表名、字段名、索引、别名)包裹,以避免與關鍵字重名!中文也可以作為辨別符!
2. 每個庫目錄存在一個儲存目前資料庫的選項檔案db.opt。
3. 注釋:
    單行注釋 # 注釋内容
    多行注釋 /* 注釋内容 */
    單行注釋 -- 注釋内容     (标準SQL注釋風格,要求雙破折号後加一空格符(空格、TAB、換行等))
4. 模式通配符:
    _   任意單個字元
    %   任意多個字元,甚至包括零字元
    單引号需要進行轉義 \'
5. CMD指令行内的語句結束符可以為 ";", "\G", "\g",僅影響顯示結果。其他地方還是用分号結束。delimiter 可修改目前對話的語句結束符。
6. SQL對大小寫不敏感
7. 清除已有語句:\c