MYSQL 全套

 

作者:張巖林

來源:www.cnblogs.com/aylin/p/5744312.html

 

MySQL簡介

 

1、什麼是數據庫 ?

 

數據庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫,它產生於距今六十多年前,隨着信息技術和市場的發展,特別是二十世紀九十年代以後,數據管理不再僅僅是存儲和管理數據,而轉變成用戶所需要的各種數據管理的方式。數據庫有很多種類型,從最簡單的存儲有各種數據的表格到能夠進行海量數據存儲的大型數據庫系統都在各個方面得到了廣泛的應用。

 

主流的數據庫有:sqlserver,mysql,Oracle、SQLite、Access、MS SQL Server等,本文主要講述的是mysql

 

2、數據庫管理是幹什麼用的?

 

  • a. 將數據保存到文件或內存

     

  • b. 接收特定的命令,然後對文件進行相應的操作

 

PS:如果有了以上管理系統,無須自己再去創建文件和文件夾,而是直接傳遞 命令 給上述軟件,讓其來進行文件操作,他們統稱爲數據庫管理系統(DBMS,Database Management System)

 

 

MySQL安裝

 

MySQL是一種開放源代碼的關係型數據庫管理系統(RDBMS),MySQL數據庫系統使用最常用的數據庫管理語言–結構化查詢語言(SQL)進行數據庫管理。在 WEB 應用方面MySQL是最好的 RDBMS (Relational Database Management System,關係數據庫管理系統) 應用軟件之一。

 

使用mysql必須具備一下條件

 

  • a. 安裝MySQL服務端

     

  • b. 安裝MySQL客戶端

     

  • c. 【客戶端】連接【服務端】

     

  • d. 【客戶端】發送命令給【服務端MySQL】服務的接受命令並執行相應操作(增刪改查等)

 

1、下載地址:http://dev.mysql.com/downloads/mysql/

 

2、安裝

 

  • windows安裝請參考:http://www.cnblogs.com/lonelywolfmoutain/p/4547115.html

     

  • linux下安裝:http://www.cnblogs.com/chenjunbiao/archive/2011/01/24/1940256.html

 

注:以上兩個鏈接有完整的安裝方式,擼主也是參考他的安裝的,安裝完以後mysql.server start啓動mysql服務

 

 

MySQL操作

 

一、連接數據庫

mysql  -u user -p                   
例:mysql -u root -p

常見錯誤如下:

 

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2), it means that the MySQL server daemon (Unix) or service (Windows) is not running.

 

退出連接:

QUIT 或者 Ctrl+D

二、查看數據庫,創建數據庫,使用數據庫查看數據庫: 

show databases;

默認數據庫:

mysql - 用戶權限相關數據
test - 用於用戶測試數據
information_schema - MySQL本身架構相關數據

創建數據庫:    

create database db1 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; # utf8編碼

create database db1 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci; # gbk編碼

使用數據庫:

 use db1;

顯示當前使用的數據庫中所有表:

SHOW TABLES;

三、用戶管理

創建用戶

create user '用戶名'@'IP地址' identified by '密碼';

刪除用戶

drop user '用戶名'@'IP地址';

修改用戶

rename user '用戶名'@'IP地址'; to '新用戶名'@'IP地址';

修改密碼

set password for '用戶名'@'IP地址' = Password('新密碼');

注:用戶權限相關數據保存在mysql數據庫的user表中,所以也可以直接對其進行操作(不建議)

 

四、權限管理

 

mysql對於權限這塊有以下限制:

all privileges:除grant外的所有權限
select:僅查權限
select,insert:查和插入權限
...
usage:無訪問權限
alter:使用alter table
alter routine:使用alter procedure和drop procedure
create:使用create table
create routine:使用create procedure
create temporary tables:使用create temporary tables
create user:使用create user、drop user、rename user和revoke  all privileges
create view:使用create view
delete:使用delete
drop:使用drop table
execute:使用call和存儲過程
file:使用select into outfile 和 load data infile
grant option:使用grant 和 revoke
index:使用index
insert:使用insert
lock tables:使用lock table
process:使用show full processlist
select:使用select
show databases:使用show databases
show view:使用show view
update:使用update
reload:使用flush
shutdown:使用mysqladmin shutdown(關閉MySQL)
super:使用change master、kill、logs、purge、master和set global。還允許mysqladmin調試登陸
replication client:服務器位置的訪問
replication slave:由複製從屬使用

對於數據庫及內部其他權限如下:

數據庫名.*            數據庫中的所有
數據庫名.表           指定數據庫中的某張表
數據庫名.存儲過程      指定數據庫中的存儲過程
*.*                   所有數據庫

對於用戶和IP的權限如下:

用戶名@IP地址        用戶只能在改IP下才能訪問
用戶名@192.168.1.%   用戶只能在改IP段下才能訪問(通配符%表示任意)
用戶名@%             用戶可以再任意IP下訪問(默認IP地址爲%)

1、查看權限:

show grants for '用戶'@'IP地址'

2、授權

grant  權限 on 數據庫.表 to   '用戶'@'IP地址'

3、取消授權

revoke 權限 on 數據庫.表 from '用戶名'@'IP地址'

授權實例如下:

grant all privileges on db1.tb1 TO '用戶名'@'IP'

grant select on db1.* TO '用戶名'@'IP'

grant select,insert on *.* TO '用戶名'@'IP'

revoke select on db1.tb1 from '用戶名'@'IP'

 

MySQL表操作

 

1、查看錶

show tables; # 查看數據庫全部表

select * from 表名; # 查看錶所有內容

2、創建表

create table 表名(
    列名  類型  是否可以爲空,
    列名  類型  是否可以爲空
)ENGINE=InnoDB DEFAULT CHARSET=utf8

來一個實例好詳解

CREATE TABLE `tab1` (
  `nid` int(11) NOT NULL auto_increment,
  `name` varchar(255) DEFAULT zhangyanlin,
  `email` varchar(255),
  PRIMARY KEY (`nid`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

注:

 

  • 默認值,創建列時可以指定默認值,當插入數據時如果未主動設置,則自動添加默認值

     

  • 自增,如果爲某列設置自增列,插入數據時無需設置此列,默認將自增(表中只能有一個自增列)注意:1、對於自增列,必須是索引(含主鍵)2、對於自增可以設置步長和起始值

     

  • 主鍵,一種特殊的唯一索引,不允許有空值,如果主鍵使用單個列,則它的值必須唯一,如果是多列,則其組合必須唯一。

 

3、刪除表

drop table 表名

4、清空表內容

delete from 表名
truncate table 表名

5、修改表

添加列:   

alter table 表名 add 列名 類型

刪除列:   

alter table 表名 drop column 列名

修改列:
          
alter table 表名 modify column 列名 類型;  -- 類型
alter table 表名 change 原列名 新列名 類型; -- 列名,類型

添加主鍵:
          
alter table 表名 add primary key(列名);

刪除主鍵:
          
alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

添加外鍵: 

alter table 從表 add constraint 外鍵名稱(形如:FK_從表_主表) foreign key 從表(外鍵字段) references 主表(主鍵字段);

刪除外鍵: 

alter table 表名 drop foreign key 外鍵名稱

修改默認值:

ALTER TABLE testalter_tbl ALTER i SET DEFAULT 1000;

刪除默認值:

ALTER TABLE testalter_tbl ALTER i DROP DEFAULT;

對於上述這些操作是不是看起來很麻煩,很浪費時間,別慌!有專門的軟件能提供這些功能,操作起來非常簡單,這個軟件名字叫Navicat Premium ,大家自行在網上下載,練練手,但是下面的即將講到表內容操作還是建議自己寫命令來進行

 

6、基本數據類型

 

MySQL的數據類型大致分爲:數值、時間和字符串

bit[(M)]
            二進制位(101001),m表示二進制位的長度(1-64),默認m=1

tinyint[(m)] [unsigned] [zerofill]

            小整數,數據類型用於保存一些範圍的整數數值範圍:
            有符號:
                -128 ~ 127.
            無符號:
                0 ~ 255

            特別的: MySQL中無布爾值,使用tinyint(1)構造。

int[(m)][unsigned][zerofill]

            整數,數據類型用於保存一些範圍的整數數值範圍:
                有符號:
                    -2147483648 ~ 2147483647
                無符號:
                    0 ~ 4294967295

            特別的:整數類型中的m僅用於顯示,對存儲範圍無限制。例如: int(5),當插入數據2時,select 時數據顯示爲:00002

bigint[(m)][unsigned][zerofill]

            大整數,數據類型用於保存一些範圍的整數數值範圍:
                有符號:
                    -9223372036854775808 ~ 9223372036854775807
                無符號:
                    0  ~  18446744073709551615

decimal[(m[,d])] [unsigned] [zerofill]

            準確的小數值,m是數字總個數(負號不算),d是小數點後個數。 m最大值爲65,d最大值爲30。

            特別的:對於精確數值計算時需要用此類型
                   decaimal能夠存儲精確值的原因在於其內部按照字符串存儲。

FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]
            
            單精度浮點數(非準確小數值),m是數字總個數,d是小數點後個數。
                無符號:
                    -3.402823466E+38 to -1.175494351E-38,
                    0
                    1.175494351E-38 to 3.402823466E+38
                有符號:
                    0
                    1.175494351E-38 to 3.402823466E+38

            **** 數值越大,越不準確 ****

DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]

            雙精度浮點數(非準確小數值),m是數字總個數,d是小數點後個數。

                無符號:
                    -1.7976931348623157E+308 to -2.2250738585072014E-308
                    0
                    2.2250738585072014E-308 to 1.7976931348623157E+308
                有符號:
                    0
                    2.2250738585072014E-308 to 1.7976931348623157E+308
            **** 數值越大,越不準確 ****


char (m)

            char數據類型用於表示固定長度的字符串,可以包含最多達255個字符。其中m代表字符串的長度。
            PS: 即使數據小於m長度,也會佔用m長度
            
varchar(m)

            varchars數據類型用於變長的字符串,可以包含最多達255個字符。其中m代表該數據類型所允許保存的字符串的最大長度,只要長度小於該最大值的字符串都可以被保存在該數據類型中。

            注:雖然varchar使用起來較爲靈活,但是從整個系統的性能角度來說,char數據類型的處理速度更快,有時甚至可以超出varchar處理速度的50%。因此,用戶在設計數據庫時應當綜合考慮各方面的因素,以求達到最佳的平衡

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

            枚舉類型,
            An ENUM column can have a maximum of 65,535 distinct elements. (The practical limit is less than 3000.)
            示例:
                CREATE TABLE shirts (
                    name VARCHAR(40),
                    size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
                );
                INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),('polo shirt','small');

set

            集合類型
            A SET column can have a maximum of 64 distinct members.
            示例:
                CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
                INSERT INTO myset (col) VALUES ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');

DATE
            
            YYYY-MM-DD(1000-01-01/9999-12-31)

TIME

            HH:MM:SS('-838:59:59'/'838:59:59')

YEAR

            YYYY(1901/2155)

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 年某時)

 

MySQL表內容操作

表內容操作無非就是增刪改查,當然用的最多的還是查,而且查這一塊東西最多,用起來最難,當然對於大神來說那就是so easy了,對於我這種小白還是非常難以靈活運用的,下面咱來一一操作一下

1、增

insert into 表 (列名,列名...) values (值,值,...)
insert into 表 (列名,列名...) values (值,值,...),(值,值,值...)
insert into 表 (列名,列名...) select (列名,列名...) from 表
例:
    insert into tab1(name,email) values('zhangyanlin','[email protected]')

2、刪

delete from 表   # 刪除表裏全部數據
delete from 表 where id=1 and name='zhangyanlin' # 刪除ID =1 和name='zhangyanlin' 那一行數據

3、改

update 表 set name = 'zhangyanlin' where id>1

4、查

select * from 表
select * from 表 where id > 1
select nid,name,gender as gg from 表 where id > 1

查這塊的條件太多太多我給列舉出來至於組合還得看大家的理解程度哈

a、條件判斷where

select * from 表 where id > 1 and name != 'aylin' and num = 12;
select * from 表 where id between 5 and 16;
select * from 表 where id in (11,22,33)
select * from 表 where id not in (11,22,33)
select * from 表 where id in (select nid from 表)

b、通配符like

select * from 表 where name like 'zhang%'  # zhang開頭的所有(多個字符串)
select * from 表 where name like 'zhang_'  # zhang開頭的所有(一個字符)

c、限制limit

select * from 表 limit 5;            - 前5行
select * from 表 limit 4,5;          - 從第4行開始的5行
select * from 表 limit 5 offset 4    - 從第4行開始的5行

d、排序asc,desc

select * from 表 order by 列 asc              - 根據 “列” 從小到大排列
select * from 表 order by 列 desc             - 根據 “列” 從大到小排列
select * from 表 order by 列1 desc,列2 asc    - 根據 “列1” 從大到小排列,如果相同則按列2從小到大排序

e、分組group by

select num from 表 group by num
select num,nid from 表 group by num,nid
select num,nid from 表  where nid > 10 group by num,nid order nid desc
select num,nid,count(*),sum(score),max(score),min(score) from 表 group by num,nid
select num from 表 group by num having max(id) > 10

特別的:group by 必須在where之後,order by之前

 

MySQL入門全套》講的是MySQL的基本操作,禁不住大家的熱情,所以進階來了。這一篇講的是進階,會有一點難以理解,本節主要內容MySQL視圖,存儲過程,函數,事務,觸發器,以及動態執行SQL。

視圖view

視圖是一個虛擬表,其內容由查詢定義。同真實的表一樣,視圖包含一系列帶有名稱的列和行數據。但是,視圖並不在數據庫中以存儲的數據值集形式存在。行和列數據來自由定義視圖的查詢所引用的表,並且在引用視圖時動態生成。對其中所引用的基礎表來說,視圖的作用類似於篩選。定義視圖的篩選可以來自當前或其它數據庫的一個或多個表,或者其它視圖。通過視圖進行查詢沒有任何限制,通過它們進行數據修改時的限制也很少。視圖是存儲在數據庫中的查詢的SQL 語句,它主要出於兩種原因:安全原因, 視圖可以隱藏一些數據。

 

1、創建視圖

--格式:CREATE VIEW 視圖名稱 AS  SQL語句
CREATE VIEW v1 AS SELET nid, name FROM tab1 WHERE nid > 4

2、刪除視圖

--格式:DROP VIEW 視圖名稱
DROP VIEW v1

3、修改視圖

-- 格式:ALTER VIEW 視圖名稱 AS SQL語句
ALTER VIEW v1 AS
SELET A.nid,B. NAME FROM tab1
LEFT JOIN B ON A.id = B.nid
LEFT JOIN C ON A.id = C.nid
WHERE tab1.id > 2

也就只是改了把create改成alter,中間的語句更換了。

4、使用視圖

使用視圖時,將其當作表進行操作即可,由於視圖是虛擬表,所以無法使用其對真實表進行創建、更新和刪除操作,僅能做查詢用。

select * from v1

存儲過程procedure

1、我們爲什麼要用存儲過程呢 ?

我們都知道應用程序分爲兩種,一種是基於web,一種是基於桌面,他們都和數據庫進行交互來完成數據的存取工作。假設現在有一種應用程序包含了這兩 種,現在要修改其中的一個查詢sql語句,那麼我們可能要同時修改他們中對應的查詢sql語句,當我們的應用程序很龐大很複雜的時候問題就出現這,不易維 護!另外把sql查詢語句放在我們的web程序或桌面中很容易遭到sql注入的破壞。而存儲例程正好可以幫我們解決這些問題。

 

2、創建存儲過程

創建存儲過程這塊主要有兩種,一種是帶參數的,一種是不帶參數的,先講不帶參數的再說不帶參數的。

 

不帶參數案例:

-- 創建存儲過程
delimiter //        --自定義語句結尾符號,因爲這裏要執行好多句sql語句,所以就得自定義,以防止出錯
create procedure p1()
BEGIN
    select * from tab1;
END//
delimiter ;         --自定義局域結尾符號結束

-- 執行存儲過程
call p1()

帶參數案例這塊主要有三個類

  • in          僅用於傳入參數用

  • out        僅用於返回值用

  • inout     既可以傳入又可以當作返回值

-- 創建存儲過程
delimiter \\
create procedure p1(
    in i1 int,                        -- 傳入參數i1
    in i2 int,                        -- 傳入參數i2
    inout i3 int,                     -- 即傳入又能得到返回值
    out r1 int                        -- 得到返回值
)
BEGIN
    DECLARE temp1 int;
    DECLARE temp2 int default 0;  
    set temp1 = 1;
    set r1 = i1 + i2 + temp1 + temp2; 
    set i3 = i3 + 100;
end\\
delimiter ;

-- 執行存儲過程
DECLARE @t1 INT default 3;           --  設置變量默認值爲3
DECLARE @t2 INT;                     --  設置變量
CALL p1 (1, 2 ,@t1, @t2);            --  執行存儲過程,並傳入參數,t2自動取消
SELECT @t1,@t2;                      --  查看存儲過程輸出結果

3、刪除存儲過程

drop procedure p1;

4、Python用pymysql模塊調用存儲過程,因爲我們學習這些就是爲了語言調用

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='day39b_')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 執行存儲過程
row = cursor.callproc('p1',(1,2,3))
# 存儲過程的查詢結果
selc = cursor.fetchall()
print(selc)
# 獲取存儲過程返回
effect_row = cursor.execute('select @_p1_0,@_p1_1,@_p1_2')
# 曲存儲過程的返回值
ret = cursor.fetchone()
print(ret)
# 提交,不然無法保存新建或者修改的數據
conn.commit()
# 關閉遊標
cursor.close()
# 關閉連接
conn.close()

函數function

在MySQL中有很多內置函數,比如我們經常用的求平均值,求和,個數,各式各樣,先給大家來一部門內置函數,然後再說說自定義函數吧,函數也可以傳參數,也可以接收返回值,但是函數沒辦法得到執行語句得到的結果,存儲過程可以。

CHAR_LENGTH(str)
        返回值爲字符串str 的長度,長度的單位爲字符。一個多字節字符算作一個單字符。
        對於一個包含五個二字節字符集, LENGTH()返回值爲 10, 而CHAR_LENGTH()的返回值爲5。

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)
        變大寫

LTRIM(str)
        返回字符串 str ,其引導空格字符被刪除。
RTRIM(str)
        返回字符串 str ,結尾空格字符被刪去。
SUBSTRING(str,pos,len)
        獲取字符串子序列

LOCATE(substr,str,pos)
        獲取子序列索引位置

REPEAT(str,count)
        返回一個由重複的字符串str 組成的字符串,字符串str的數目等於count 。
        若 count <= 0,則返回一個空字符串。
        若str 或 count 爲 NULL,則返回 NULL 。
REPLACE(str,from_str,to_str)
        返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
REVERSE(str)
        返回字符串 str ,順序和字符順序相反。
RIGHT(str,len)
        從字符串str 開始,返回從後邊開始len個字符組成的子序列

SPACE(N)
        返回一個由N空格組成的字符串。

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'

TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
        返回字符串 str , 其中所有remstr 前綴和/或後綴都已被刪除。若分類符BOTH、LEADIN或TRAILING中沒有一個是給定的,則假設爲BOTH 。 remstr 爲可選項,在未指定情況下,可刪除空格。

        mysql> SELECT TRIM('  bar   ');
                -> 'bar'

        mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
                -> 'barxxx'

        mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
                -> 'bar'

        mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
                -> 'barx'

更多參考請參考中文文檔【http://doc.mysql.cn/mysql5/refman-5.1-zh.html-chapter/functions.html#encryption-functions】

1、自定義創建函數

delimiter \\
create function f1(
    i1 int,
    i2 int)
returns int
BEGIN
    declare num int;
    set num = i1 + i2;
    return(num);
END \\
delimiter ;

2、刪除函數

drop function f1;

3、執行函數

# 獲取返回值
declare @i VARCHAR(32);
select UPPER('alex') into @i;
SELECT @i;

# 在查詢中使用
select f1(11,nid) ,name from tb2;

 

事務

事務用於將某些操作的多個SQL作爲原子性操作,一旦有某一個出現錯誤,即可回滾到原來的狀態,從而保證數據庫數據完整性。例如:當兩張銀行卡之間進行轉賬,甲方錢轉出去了,突然光纜壞了,乙方還沒收到錢,錢跑哪裏去了,就爲了防止這種情況,事務就出來了,事務可以防止這種事情發生。

 

應用事務實例:

delimiter \\
create PROCEDURE p1(
    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; 
    DELETE from tb1;                   -- sql語句都放在這個裏面
    insert into tb2(name)values('seven');
  COMMIT; 

  -- SUCCESS 
  set p_return_code = 0; 

  END\\
delimiter ;

執行存儲過程:

DECLARE @i TINYINT;
call p1(@i);
select @i;

 

觸發器TRIGGER

觸發器,簡單來說就是當你在執行這條語句之前或者之後觸發一次增刪改查,觸發器用於定製用戶對錶的行進行【增/刪/改】前後的行爲。

 

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

例一插入前:

-- 在往tab1插入數據之前往tab2中插入一條name = 張巖林,當然是在判斷往tab1中插入的名字是不是等於aylin
delimiter //
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN

IF NEW. NAME == 'aylin' THEN
    INSERT INTO tb2 (NAME)
VALUES
    ('張巖林')
END
END//
delimiter ;

示例二插入後:

delimiter //
CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
BEGIN
    IF NEW. num = 666 THEN
        INSERT INTO tb2 (NAME)
        VALUES
            ('張巖林'),
            ('很帥') ;
    ELSEIF NEW. num = 555 THEN
        INSERT INTO tb2 (NAME)
        VALUES
            ('aylin'),
            ('非常帥') ;
    END IF;
END//
delimiter ;

同樣的刪,改,查都是同樣的道理。

 

特別的:NEW表示即將插入的數據行,OLD表示即將刪除的數據行。

 

2、刪除觸發器

DROP TRIGGER tri_after_insert_tb1;

3、使用觸發器

觸發器無法由用戶直接調用,而知由於對錶的【增/刪/改】操作被動引發的。

insert into tb1(name) values(‘張巖林’)

 

最近做的項目與數據庫關係密切,自然少不了很多SQL。下面總結一下最近使用的能夠較大提升工作效率的SQL。

 

1、根據表2的某個字段來更新表1的某個字段

 

這是一個坑,錯誤的寫法是

update table_name_1 T1
  set column_name_1 =
      (select column_name_2 from table_name_2 T2 where T1.id = t2.id);

這種寫法的錯誤之處在於,對於T1.id = t2.id,會從表2中的字段取出column_name_2來更新表1中的column_name_1的,而對於表1中的id不在表2中的,則會被設置爲null。這樣的風險是很高的。那麼,如何避免這種情形呢?正確的寫法是什麼呢?

update table_name_1 T1
  set column_name_1 =
      (select column_name_2 from table_name_2 T2 where T1.id = t2.id)
where exists (select 1 from table_name_2 T2 where T1.id = T2.id);

增加了一句話, where exists (select 1 from table_name_2 T2 where T1.id = T2.id), 這樣的結果就是,當T1中的id存在在T2中時,則進行更新,否則,不會進行更新。

2、Oracle中的列轉行

 

在表的設計中,通常會遇到這樣的場景:某一行代表一個權限,比如用戶A擁有權限A,B,C總共用三行數據。在統計的過程中,我們想查看用戶A究竟總共有哪些權限呢?這就用到了Oracle中的列轉行。

用法如下:

LISTAGG(column_name,',') WITHIN GROUP( ORDER BY column_name)

可以通過如下例子來理解:

with A as
(select 'LiMing' name, 'Qualification1' qualification
   from dual
 union all
 select 'LiMing' name, 'Qualification2' qualification
   from dual
 union all
 select 'LiMing' name, 'Qualification3' qualification
   from dual
 union all
 select 'HanMeimei' name, 'Qualification2' qualification
   from dual
 union all
 select 'HanMeimei' name, 'Qualification4' qualification
   from dual
 union all
 select 'Tom' name, 'Qualification1' qualification
   from dual)
select name,
      listagg(qualification, ',') within GROUP(order by qualification) as "qualification"
 from A
group by name

 

 

 

3、 WITH AS 用法

 

有的時候,我們需要涉及到多表關聯查詢,然後將查詢的結果進行彙總。那麼,這種場景下,with as語法就非常有用。

with table_name_1 as
(select .. ..),
table_name_2 as
(select .. ..),
table_name_3 as
(select .. ..)
select .. . from table_name_1, table_name_2, table_name_3

這樣寫最大的好處是邏輯特別清晰,要查的數據不會因爲多表關聯或者join使得邏輯不清晰出現BUG。另外一大好處就是一次查詢,多次使用。將查詢結果放在臨時表裏面,後續可以對此表多次分析使用。

 

4、左連接LEFT JOIN

 

LEFT JOIN 關鍵字會從左表 (table_name_1) 那裏返回所有的行,即使在右表 (table_name_2) 中沒有匹配的行。此種場景下,如果採用多表關聯查詢,可能會丟失沒有匹配的數據,所以,這種情況要採用左連接。

 

具體語法如下:

SELECT *
  FROM table_name_1
  LEFT JOIN table_name_2
    ON table_name_1.column_name = table_name_2.column_name

 

索引簡介

 索引是對數據庫表中一個或多個列(例如,employee 表的姓名 (name) 列)的值進行排序的結構。如果想按特定職員的姓來查找他或她,則與在表中搜索所有的行相比,索引有助於更快地獲取信息。

 

例如這樣一個查詢:select * from table1 where id=10000。如果沒有索引,必須遍歷整個表,直到ID等於10000的這一行被找到爲止;有了索引之後(必須是在ID這一列上建立的索引),即可在索引中查找。由於索引是經過某種算法優化過的,因而查找次數要少的多。可見,索引插敘的速度要比沒有索引的速度要快很多。

 

MySQL中常見索引有:

  • 普通索引

  • 唯一索引

  • 主鍵索引

  • 組合索引

 

 下面就應用一下索引吧

索引操作

 一、普通索引(index)

普通所以只有一個功能,就是加快查找速度。操作如下:

 

1、先創建一個表

create table tab1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
)

2、創建索引

create index 索引名稱 on 表名(列名)

3、刪除索引

drop 索引名稱 on 表名;

4、查看索引

show index from 表名;

5、注意事項(對於創建索引時如果是BLOB 和 TEXT 類型,必須指定length)

create index index_name on tab1(extra(32));

二、唯一索引(unique)

唯一性索引unique index和一般索引normal index最大的差異就是在索引列上增加了一層唯一約束。添加唯一性索引的數據列可以爲空,但是隻要存在數據值,就必須是唯一的。

 

1、創建表+唯一索引

create table tab2(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    unique ix_name (name)  ## 重點在這裏
)

2、創建索引

create unique index 索引名 on 表名(列名)

3、刪除索引

drop unique index 索引名 on 表名

三、主鍵索引

在數據庫關係圖中爲表定義一個主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特殊類型。主鍵索引要求主鍵中的每個值是唯一的。當在查詢中使用主鍵索引時,它還允許快速訪問數據。數據不能爲空。

 

1、創建表+主鍵索引

create table in1(
    nid int not null auto_increment,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    primary key(nid),
    index zhang (name)
)

2、創建主鍵

alter table 表名 add primary key(列名);

3、刪除主鍵

alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

四、組合索引

組合索引,就是組合查詢的意思嘛嘻嘻,將兩列或者多列組合成一個索引進行查詢。

其應用場景爲:頻繁的同時使用n列來進行查詢,如:where name = '張巖林' and email = 666。

 

1、創建表

create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
)

2、創建組合索引

create index ix_name_email on in3(name,email);

如上創建組合索引之後,查詢有的會使用索引,有的不會:

 

  • name and email  -- 使用索引

  • name                 -- 使用索引

  • email                 -- 不使用索引

 

索引注意事項

一、正確使用索引

數據庫表中添加索引後能夠讓查詢數據庫速度飛快,但前提必須是正確的使用索引來查詢,如果以錯誤的方式使用,則即使建立索引也會不奏效。

 

下面這些情況不會使用到索引:

 

1、like '%xx'

select * from tb1 where name like '%cn';

2、使用函數

select * from tb1 where reverse(name) = '張巖林';

3、or

select * from tb1 where nid = 1 or email='[email protected]';
特別的:當or條件中有未建立索引的列才失效,以下會走索引
     select * from tb1 where nid = 1 or name = 'zhangyanlin';
     select * from tb1 where nid = 1 or email = '[email protected]' and name = 'aylin'

4、類型不一致

如果列是字符串類型,傳入條件是必須用引號引起來,不然...
select * from tb1 where name = 999;

5、!=

select * from tb1 where name != 'aylin'
特別的:如果是主鍵,則還是會走索引
     select * from tb1 where nid != 123

6、>

select * from tb1 where name > 'alex'
特別的:如果是主鍵或索引是整數類型,則還是會走索引
     select * from tb1 where nid > 123
     select * from tb1 where num > 123

7、order by

select email from tb1 order by name desc;
當根據索引排序時候,選擇的映射如果不是索引,則不走索引
特別的:如果對主鍵排序,則還是走索引:
     select * from tb1 order by nid desc;

8、組合索引最左前綴

如果組合索引爲:(name,email)
name and email       -- 使用索引
name                 -- 使用索引
email                -- 不使用索引

二、其它注意事項

 

  • 避免使用select *

  • count(1)或count(列) 代替 count(*)

  • 創建表時儘量時 char 代替 varchar

  • 表的字段順序固定長度的字段優先

  • 組合索引代替多個單列索引(經常使用多個條件查詢時)

  • 儘量使用短索引

  • 使用連接(JOIN)來代替子查詢(Sub-Queries)

  • 連表時注意條件類型需一致

  • 索引散列值(重複少)不適合建索引,例:性別不適合

     

三、執行計劃

Explain + 查詢SQL - 用於顯示SQL執行信息參數,根據參考信息可以進行SQL優化:

mysql> explain select * from tb2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

詳細介紹如下:

id
        
        查詢順序標識
            如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
            |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
        特別的:如果使用union連接氣值可能爲null

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 tb1;
            特別的:如果有limit限制,則找到之後就不在繼續向下掃描
                select * from tb1 where email = '[email protected]'
                select * from tb1 where email = '[email protected]' limit 1;
                雖然上述兩個語句都會進行全表掃描,第二句使用了limit,則找到一個後就不再繼續掃描。

    INDEX  全索引掃描,對索引從頭到尾找一遍
           select nid from tb1;

    RANGE  對索引列進行範圍查找
           select *  from tb1 where name < 'alex';
           PS:
             between and
             in
             >   >=  <   <=  操作
             注意:!= 和 > 符號

    INDEX_MERGE 合併索引,使用多個單列索引搜索
                select *  from tb1 where name = 'alex' or nid in (11,22,33);

    REF   根據索引查找一個或多個值
          select *  from tb1 where name = 'seven';

    EQ_REF  連接時使用primary key 或 unique類型
            select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;

    CONST  常量
           表最多有一個匹配行,因爲僅有一行,在這行的列值可被優化器剩餘部分認爲是常數,const表很快,因爲它們只讀取一次。
           select nid from tb1 where nid = 2 ;

    SYSTEM 系統
           表僅有一行(=系統表)。這是const聯接類型的一個特例。
           select * from (select nid from tb1 where nid = 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列中索引的位圖,並且是冗餘的。

四、limit分頁

分頁功能是個值得關注的問題,因爲我們會一直用到:

每頁顯示10條:

倒序:
            大            小
            980    970   960
 
下一頁:

    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid < 當前頁最小值 order by nid desc limit 每頁數據 *【頁碼-當前頁】) A order by A.nid asc limit 1)  
    order by 
        nid desc 
    limit 10;

    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid < 970  order by nid desc limit 40) A order by A.nid asc limit 1)  
    order by 
        nid desc 
    limit 10;

上一頁:

    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid > 當前頁最大值 order by nid asc limit 每頁數據 *【當前頁-頁碼】) A order by A.nid asc limit 1)  
    order by 
        nid desc 
    limit 10;

    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid > 980 order by nid asc limit 20) A order by A.nid desc limit 1)  
    order by 
        nid desc 
    limit 10;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章