1. 程式人生 > >第八章| 3. MyAQL資料庫|Navicat工具與pymysql模組

第八章| 3. MyAQL資料庫|Navicat工具與pymysql模組

1、Navicat工具與pymysql模組

在生產環境中操作MySQL資料庫還是推薦使用命令列工具mysql,但在我們自己開發測試時,可以使用視覺化工具Navicat,以圖形介面的形式操作MySQL資料庫

掌握:
#1. 測試+連結資料庫
#2. 新建庫
#3. 新建表,新增欄位+型別+約束
#4. 設計表:外來鍵
#5. 新建查詢
#6. 備份庫/表

#注意:
批量加註釋:ctrl+?鍵
批量去註釋:ctrl+shift+?鍵

之前我們都是通過MySQL自帶的命令列客戶端工具mysql來操作資料庫,那如何在python程式中操作資料庫呢?這就用到了pymysql模組,該模組本質就是一個套接字客戶端軟體,使用前需要事先安裝   pip3 install pymysql

import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip()

# 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿到遊標
cursor=conn.cursor()

# 執行sql語句
# sql='select * from userinfo where user = "%s" and pwd="%s"' %(user,pwd)
# print(sql) sql='select * from userinfo where user = %s and pwd=%s' rows=cursor.execute(sql,(user,pwd)) #提交給遊標執行 execute這個介面拿到的是2 rows in set (0.00 sec) 2那個行數,如果值不為0說明就輸對了 cursor.close() conn.close() # 進行判斷 if rows: print('登入成功') else: print('登入失敗')
View Code

mysql語句中 -- xfjl ,-- + 空格後邊的都給你註釋掉了

import pymysql
user=input('使用者名稱: ').strip()
pwd=input('密碼: ').strip()

#連結
conn=pymysql.connect(host='localhost',user='root',password='123',database='egon',charset='utf8')
#遊標
cursor=conn.cursor() #執行完畢返回的結果集預設以元組顯示
#cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)


#執行sql語句
sql='select * from userinfo where name="%s" and password="%s"' %(user,pwd) #注意%s需要加引號
print(sql)
res=cursor.execute(sql) #執行sql語句,返回sql查詢成功的記錄數目
print(res)

cursor.close()
conn.close()

if res:
    print('登入成功')
else:
    print('登入失敗')


列印: #兩種執行的錯誤
user>>: egon" -- xxxhhhh
password>>: 
select * from userinfo where user = "egon" -- xxxhhhh" and pwd=""
登入成功


user>>: xxxx" or 1=1 -- hhhhhaaa
password>>: 
select * from userinfo where user = "xxxx" or 1=1 -- hhhhhaaa" and pwd=""
登入成功
View Code

改正:

import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip()

# 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿到遊標
cursor=conn.cursor()

# 執行sql語句
# sql='select * from userinfo where user = "%s" and pwd="%s"' %(user,pwd)
# print(sql)
# rows=cursor.execute(sql)

sql='select * from userinfo where user = %s and pwd=%s'
#由execute作為拼接,不用你自己去拼接了,在拼接過程中給你過濾掉這種非法操作
rows=cursor.execute(sql,(user,pwd)) #提交給遊標執行  execute這個介面拿到的是2 rows in set (0.00 sec) 2那個行數,如果值不為0說明就輸對了

cursor.close()
conn.close()

# 進行判斷
if rows:
    print('登入成功')
else:
    print('登入失敗')
View Code

增加

import pymysql

# 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿遊標
cursor=conn.cursor()

# 執行sql
# 增、刪、改  對資料的變動
sql='insert into userinfo(user,pwd) values(%s,%s)'
rows=cursor.execute(sql,('wxx','123'))
print(rows)


conn.commit() #必須加上這個
# 關閉
cursor.close()
conn.close()

列印:
View Code
#1、增刪改
import pymysql

# 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿遊標
cursor=conn.cursor()

# 執行sql
# 增、刪、改  對資料的變動
sql='insert into userinfo(user,pwd) values(%s,%s)'
# rows=cursor.execute(sql,('wxx','123'))
# print(rows)
rows=cursor.executemany(sql,[('yxx','123'),('egon1','111'),('egon2','2222')]) #可以插入多條
print(rows)

conn.commit() #必須加上這個
# 關閉
cursor.close()
conn.close()

列印
View Code
#2、查詢
import pymysql
# # 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿遊標
cursor=conn.cursor(pymysql.cursors.DictCursor) #基於字典形式的遊標,不加括號內的是以元組形式

# 執行sql
# 查詢
rows=cursor.execute('select * from userinfo;') #把字串send給服務端,在服務端把這個sql語句執行下,然後把結果丟給客戶端
print(rows)
# print(cursor.fetchone()) #代表取一行
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())

#print(cursor.fetchmany(2)) #指定取的個數,以列表的形式

#print(cursor.fetchall()) #拿出所有,列表的形式
# print(cursor.fetchall())

cursor.scroll(3,mode='absolute') #移動游標 相對絕對位置移動,從頭數3個開始取出來1個,結果是第4個
#print(cursor.fetchone())
cursor.scroll(2,mode='relative') # 相對當前位置移動 往後跳2位
print(cursor.fetchone())
# 關閉
cursor.close()
conn.close()

列印:
{'id': 6, 'user': 'egon2', 'pwd': '2222'}
View Code
import pymysql
#
# # 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)
#
# # 拿遊標
cursor=conn.cursor()

sql='insert into userinfo(user,pwd) values(%s,%s)'

rows=cursor.executemany(sql,[('egon3','123'),('egon4','111'),('egon5','2222')])
print(cursor.lastrowid) #插入之前游標走到哪裡了
#
conn.commit() #必須加上這個
# 關閉
cursor.close()
conn.close()

列印:
View Code

涉及資料庫的操作的,先要編寫好資料,然後基於pymysql模組幫我把sql語句提交給mysql服戶端,執行完之後把結果再返回到應用程式中再做進一步的處理;將應用程式的開發與資料庫的開發結合

2、mysql內建函式功能

  檢視是一個虛擬表(非真實存在),其本質是【根據SQL語句獲取動態的資料集,併為其命名】,使用者使用時只需使用【名稱】即可獲取結果集,可以將該結果集當做表來使用。

  使用檢視我們可以把查詢過程中的臨時表摘出來,用檢視去實現,這樣以後再想操作該臨時表的資料時就無需重寫複雜的sql了,直接去檢視中查詢即可,但檢視有明顯地效率問題,並且檢視是存放在資料庫中的,如果我們程式中使用的sql過分依賴資料庫中的檢視,即強耦合,那就意味著擴充套件sql極為不便,因此並不推薦使用

  檢視 只有表結構frm,沒有資料,因為是查出來的虛擬表;不用重複寫,但是不建議使用,如果有好多個檢視,要找到所有的檢視給它修改很麻煩;

mysql> use db7;
Database changed
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 | alex            |
+-----+-----------------+
rows in set (0.00 sec)

mysql> select * from course inner join teacher on course.teacher_id=teacher.tid;
+-----+--------+------------+-----+-----------------+
| cid | cname  | teacher_id | tid | tname           |
+-----+--------+------------+-----+-----------------+
|   1 | 生物   |          1 |   1 | 張磊老師        |
|   2 | 物理   |          2 |   2 | 李平老師        |
|   4 | 美術   |          2 |   2 | 李平老師        |
|   3 | 體育   |          3 |   3 | 劉海燕老師      |
+-----+--------+------------+-----+-----------------+
rows in set (0.10 sec)

mysql> create view course2teacher as select * from course inner join teacher on course.teacher_id=teacher.tid;
Query OK, 0 rows affected (0.20 sec)

mysql> show tables;
+----------------+
| Tables_in_db7  |
+----------------+
| course         |
| course2teacher |
| teacher        |
+----------------+
rows in set (0.00 sec)

mysql>
View Code

觸發器

使用觸發器可以定製使用者對錶進行【增、刪、改】操作時前後的行為,注意:沒有查詢

mysql> create database db11;
Query OK, 1 row affected (0.00 sec)

mysql> use db11;
Database changed
mysql> 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代表執行失敗
    -> );
Query OK, 0 rows affected (0.77 sec)

mysql>
mysql> CREATE TABLE errlog (
    ->     id INT PRIMARY KEY auto_increment,
    ->     err_cmd CHAR (64),
    ->     err_time datetime
    -> );
Query OK, 0 rows affected (0.68 sec)

#建立觸發器
mysql> delimiter //
mysql> 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//
Query OK, 0 rows affected (0.34 sec)
mysql> delimiter ;
mysql>
mysql>
mysql>#往cmd中插入記錄,觸動觸發器,根據IF條件決定是否插入錯誤日誌
mysql> 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');
Query OK, 4 rows affected (0.43 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from cmd; +----+------+------+-----------------+---------------------+---------+
| id | USER | priv | cmd             | sub_time            | success |
+----+------+------+-----------------+---------------------+---------+
|  1 | egon | 0755 | ls -l /etc      | 2018-04-28 18:26:33 | yes     |
|  2 | egon | 0755 | cat /etc/passwd | 2018-04-28 18:26:33 | no      |
|  3 | egon | 0755 | useradd xxx     | 2018-04-28 18:26:33 | no      |
|  4 | egon | 0755 | ps aux          | 2018-04-28 18:26:33 | yes     |
+----+------+------+-----------------+---------------------+---------+
rows in set (0.00 sec)

mysql> select * from errlog; #查詢錯誤日誌發現有兩條
+----+-----------------+---------------------+
| id | err_cmd         | err_time            |
+----+-----------------+---------------------+
|  1 | cat /etc/passwd | 2018-04-28 18:26:33 |
|  2 | useradd xxx     | 2018-04-28 18:26:33 |
+----+-----------------+---------------------+
rows in set (0.00 sec)
View Code

儲存過程

把mysql處理好的資料給封裝好,一個介面名,應用程式可以直接呼叫介面,這個介面就叫儲存過程。是mysql內建功能的一系列總和;

儲存過程包含了一系列可執行的sql語句,儲存過程存放於MySQL中,通過呼叫它的名字可以執行其內部的一堆sql

使用儲存過程的優點:

1. 用於替代程式寫的SQL語句,實現程式與sql解耦

2. 基於網路傳輸,傳別名的資料量小,而直接傳sql資料量大

使用儲存過程的缺點:

1. 程式設計師擴充套件功能不方便

程式與資料庫結合使用的三種方式:

建立簡單的儲存過程:

#1、無參儲存過程
    delimiter //
    create procedure p1()
    BEGIN
        select * from db7.teacher;
    END //
    delimiter ;
mysql> use db7;
Database changed
mysql> delimiter //
mysql> create procedure p1()
    -> BEGIN
    -> select * from db7.teacher;
    -> END //
Query OK, 0 rows affected (0.21 sec)

mysql> delimiter ;
mysql>
mysql>
mysql> show create procedure p1;
+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------+----------------------+----------------------+------
--------------+
| Procedure | sql_mode                                   | Create Procedure                                                                        | character_set_client | collation_connection | Datab
ase Collation |
+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------+----------------------+----------------------+------
--------------+
| p1        | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
BEGIN
select * from db7.teacher;
END | utf8                 | utf8_general_ci      | utf8_general_ci    |
+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------+----------------------+----------------------+------
--------------+
row in set (0.00 sec)
View Code
# MySQL中呼叫
  call p1();  
mysql> call p1();
+-----+-----------------+
| tid | tname           |
+-----+-----------------+
|   1 | 張磊老師        |
|   2 | 李平老師        |
|   3 | 劉海燕老師      |
|   4 | 朱雲海老師      |
|   5 | alex            |
+-----+-----------------+
rows in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)
View Code
# Python中呼叫
import pymysql

# 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db7',
    charset='utf8'
)

# 拿遊標
cursor=conn.cursor()

# 執行sql
cursor.callproc('p1') #只是執行
print(cursor.fetchall())

列印
((1, '張磊老師'), (2, '李平老師'), (3, '劉海燕老師'), (4, '朱雲海老師'), (5, 'alex'))
View Code
#2、有參儲存過程   #在mysql中引數必須指定型別,是用來接收值的還是返回值的
對於儲存過程,可以接收引數,其引數有三類:
#in          僅用於傳入引數用
#out        僅用於返回值用
#inout     既可以傳入又可以當作返回值
delimiter //
    create procedure p2(in n1 int,in n2 int,out res int) #當儲存過程p1執行完了,就把res當做返回值返回了這就是out的作用,只有out的值才能被返回
    BEGIN
        select * from db7.teacher where tid > n1 and tid < n2;
        set res = 1;
    END //
    delimiter ;


    # MySQL中呼叫
    set @x=0 #初始值等於零
    call p2(2,4,@x);
    select @x;檢視結果

    # Python中呼叫
    cursor.callproc('p2',(2,4,0))# @_p2_0=2,@_p2_1=4,@_p2_2=0
    cursor.execute('select @_p3_2')
    cursor.fetchone()
mysql> delimiter //
mysql> create procedure p2(in n1 int, in n2 int, out res int)
    -> BEGIN
    -> select * from db7.teacher where tid > n1 and tid < n2;
    -> set res = 1;
    -> END //
Query OK, 0 rows affected (0.06 sec)

mysql> delimiter ;

mysql> set @x=0;
Query OK, 0 rows affected (0.00 sec)

mysql> call p2(2,4,@x);
+-----+-----------------+
| tid | tname           |
+-----+-----------------+
|   3 | 劉海燕老師      |
+-----+-----------------+
row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql> select @x;
+------+
| @x   |
+------+
|    1 |
+------+
row in set (0.00 sec)
View Code
import pymysql

# 建立連結
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db7',
    charset='utf8'
)

# 拿遊標
cursor=conn.cursor()

#
cursor.execute('select @_p2_2')
print(cursor.fetchone())

# 關閉
cursor.close()
conn.close()

列印
(1, )
View Code
應用程式與資料庫結合使用
方式一: (很少用,部門之間溝通效率不高;優點很好解開了耦合,效率最高)
    Python:呼叫儲存過程
    MySQL:編寫儲存過程

    
方式二:
    Python:編寫純生SQL  (可維護性好,都是開發人員寫的,)
    MySQL:
    
方式三:
    Python:ORM->純生SQL (開發效率高,可維護性高,用類,ORM框架)
    MySQL:

事務

同時成功同時失敗;

 事務用於將某些操作的多個SQL作為原子性操作,一旦有某一個出現錯誤,即可回滾到原來的狀態,從而保證資料庫資料完整性。

mysql> create table user(
    -> id int primary key auto_increment,
    -> name char(32),
    -> balance int
    -> );
Query OK, 0 rows affected (1.98 sec)

mysql>
mysql> insert into user(name,balance)
    -> values
    -> ('wsb',1000),
    -> ('egon',1000),
    -> ('ysb',1000);
Query OK, 3 rows affected (0.50 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |    1000 |
|  2 | egon |    1000 |
|  3 | ysb  |    1000 |
+----+------+---------+
rows in set (0.00 sec)

#原子操作
mysql> start transaction;
Query OK, 0 rows affected (0.05 sec)

mysql> update user set balance=900 where name='wsb'; #買支付100元
Query OK, 1 row affected (0.11 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1010 where name='egon'; #中介拿走10元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1090 where name='ysb'; #賣家拿到90元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |     900 |
|  2 | egon |    1010 |
|  3 | ysb  |    1090 |
+----+------+---------+
rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.16 sec)

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |     900 |
|  2 | egon |    1010 |
|  3 | ysb  |    1090 |
+----+------+---------+
rows in set (0.00 sec)

mysql> rollback; #出現異常就回滾到初始狀態
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |     900 |
|  2 | egon |    1010 |
|  3 | ysb  |    1090 |
+----+------+---------+
rows in set (0.00 sec)
View Code

函式與流程控制

函式

一、數學函式
    ROUND(x,y)
        返回引數x的四捨五入的有y位小數的值

    RAND()
        返回0到1內的隨機值,可以通過提供一個引數(種子)使RAND()隨機數生成器生成一個指定的值。

二、聚合函式(常用於GROUP BY從句的SELECT查詢中)
    AVG(col)返回指定列的平均值
    COUNT(col)返回指定列中非NULL值的個數
    MIN(col)返回指定列的最小值
    MAX(col)返回指定列的最大值
    SUM(col)返回指定列的所有值之和
    GROUP_CONCAT(col) 返回由屬於一組的列值連線組合而成的結果    

三、字串函式

    CHAR_LENGTH(str)
        返回值為字串str 的長度,長度的單位為字元。一個多位元組字元算作一個單字元。
    CONCAT(str1,str2,...)
        字串拼接
        如有任何一個引數為NULL ,則返回值為 NULL。
    CONCAT_WS(separator,str1,str2,...)
        字串拼接(自定義連線符)
        CONCAT_WS()不會忽略任何空字串。 (然而會忽略所有的 NULL)。

    CONV(N,from_base,to_base)
        進位制轉換
        例如:
            SELECT CONV('a',16,2); 表示將 a 由16進位制轉換為2進位制字串表示

    FORMAT(X,D)
        將數字X 的格式寫為'#,###,###.##',以四捨五入的方式保留小數點後 D 位, 並將結果以字串的形式返回。若  D 為 0, 則返回結果不帶有小數點,或不含小數部分。
        例如:
            SELECT FORMAT(12332.1,4); 結果為: '12,332.1000'
    INSERT(str,pos,len,newstr)
        在str的指定位置插入字串
            pos:要替換位置其實位置
            len:替換的長度
            newstr:新字串
        特別的:
            如果pos超過原字串長度,則返回原字串
            如果len超過原字串長度,則由新字串完全替換
    INSTR(str,substr)
        返回字串 str 中子字串的第一個出現位置。

    LEFT(str,len)
        返回字串str 從開始的len位置的子序列字元。

    LOWER(str)
        變小寫

    UPPER(str)
        變大寫

    REVERSE(str)
        返回字串 str ,順序和字元順序相反。

    SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
        不帶有len 引數的格式從字串str返回一個子字串,起始於位置 pos。帶有len引數的格式從字串str返回一個長度同len字元相同的子字串,起始於位置 pos。 使用 FROM的格式為標準 SQL 語法。也可能對pos使用一個負值。假若這樣,則子字串的位置起始於字串結尾的pos 字元,而不是字串的開頭位置。在以下格式的函式中可以對pos 使用一個負值。

        mysql> SELECT SUBSTRING('Quadratically',5);
            -> 'ratically'

        mysql> SELECT SUBSTRING('foobarbar' FROM 4);
            -> 'barbar'

        mysql> SELECT SUBSTRING('Quadratically',5,6);
            -> 'ratica'

        mysql> SELECT SUBSTRING('Sakila', -3);
            -> 'ila'

        mysql> SELECT SUBSTRING('Sakila', -5, 3);
            -> 'aki'

        mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
            -> 'ki'

四、日期和時間函式
    CURDATE()或CURRENT_DATE() 返回當前的日期
    CURTIME()或CURRENT_TIME() 返回當前的時間
    DAYOFWEEK(date)   返回date所代表的一星期中的第幾天(1~7)
    DAYOFMONTH(date)  返回date是一個月的第幾天(1~31)
    DAYOFYEAR(date)   返回date是一年的第幾天(1~366)
    DAYNAME(date)   返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
    FROM_UNIXTIME(ts,fmt)  根據指定的fmt格式,格式化UNIX時間戳ts
    HOUR(time)   返回time的小時值(0~23)
    MINUTE(time)   返回time的分鐘值(0~59)
    MONTH(date)   返回date的月份值(1~12)
    MONTHNAME(date)   返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
    NOW()    返回當前的日期和時間
    QUARTER(date)   返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
    WEEK(date)   返回日期date為一年中第幾周(0~53)
    YEAR(date)   返回日期date的年份(1000~9999)

    重點:
    DATE_FORMAT(date,format) 根據format字串格式化date值

       mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
        -> 'Sunday October 2009'
       mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
        -> '22:23:00'
       mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
        ->                 '%D %y %a %d %m %b %j');
        -> '4th 00 Thu 04 10 Oct 277'
       mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
        ->                 '%H %k %I %r %T %S %w');
        -> '22 22 10 10:23:00 PM 22:23:00 00 6'
       mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
        -> '1998 52'
       mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
        -> '00'

五、加密函式
    MD5()    
        計算字串str的MD5校驗和
    PASSWORD(str)   
        返回字串str的加密版本,這個加密過程是不可逆轉的,和UNIX密碼加密過程使用不同的演算法。

六、控制流函式            
    CASE WHEN[test1] THEN [result1]...ELSE [default] END
        如果testN是真,則返回resultN,否則返回default
    CASE [test] WHEN[val1] THEN [result]...ELSE [default]END  
        如果test和valN相等,則返回resultN,否則返回default

    IF(test,t,f)   
        如果test是真,返回t;否則返回f

    IFNULL(arg1,arg2) 
        如果arg1不是空,返回arg1,否則返回arg2

    NULLIF(arg1,arg2) 
        如果arg1=arg2返回NULL;否則返回arg1
View Code
mysql> CREATE TABLE blog (
    ->     id INT PRIMARY KEY auto_increment,
    ->     NAME CHAR (32),
    ->     sub_time datetime
    -> );
Query OK, 0 rows affected (0.78 sec)

mysql> INSERT INTO blog (NAME, sub_time)
    -> VALUES
    ->     ('第1篇','2015-03-01 11:31:21'),
    ->     ('第2篇','2015-03-11 16:31:21'),
    ->     ('第3篇','2016-07-01 10:21:31'),
    ->     ('第4篇','2016-07-22 09:23:21'),
    ->     ('第5篇','2016-07-23 10:11:11'),
    ->     ('第6篇','2016-07-25 11:21:31'),
    ->     ('第7篇','2017-03-01 15:33:21'),
    ->     ('第8篇','2017-03-01 17:32:21'),
    ->     ('第9篇','2017-03-01 18:31:21');
Query OK, 9 rows affected (0.14 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> SELECT DATE_FORMAT(sub_time,'%Y-%m'),COUNT(1) FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y-%m');
+-------------------------------+----------+
| DATE_FORMAT(sub_time,'%Y-%m') | COUNT(1) |
+-------------------------------+----------+
| 2015-03                       |        2 |
| 2016-07                       |        4 |
| 2017-03                       |        3 |
+-------------------------------+----------+
rows in set (0.22 sec)

mysql>
View Code

流程控制

delimiter //
CREATE PROCEDURE proc_if ()
BEGIN

    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END //
delimiter ;

if條件語句
View Code

3、索引原理

索引在MySQL中也叫做“鍵”,是儲存引擎用於快速找到記錄的一種資料結構。

索引相當於字典的音序表,如果要查某個字,如果不使用音序表,則需要從幾百頁中逐頁去查。

若索引太多,應用程式的效能可能會受到影響。而索引太少,對查詢效能又會產生影響,要找到一個平衡點,這對應用程式的效能至關重要。

索引的目的在於提高查詢效率,與我們查閱圖書所用的目錄是一個道理:先定位到章,然後定位到該章下的一個小節,然後找到頁數。相似的例子還有:查字典,查火車車次,飛機航班等

本質都是:通過不斷地縮小想要獲取資料的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,我們可以總是用同一種查詢方式來鎖定資料。

資料庫複雜的多,因為不僅面臨著等值查詢,還有範圍查詢(>、<、between、in)、模糊查詢(like)、並集查詢(or)等等。資料庫應該選擇怎麼樣的方式來應對所有的問題呢?我們回想字典的例子,能不能把資料分成段,然後分段查詢呢?最簡單的如果1000條資料,1到100分成第一段,101到200分成第二段,201到300分成第三段......這樣查第250條資料,只要找第三段就可以了,一下子去除了90%的無效資料。但如果是1千萬的記錄呢,分成幾段比較好?稍有演算法基礎的同學會想到搜尋樹,其平均複雜度是lgN,具有不錯的查詢效能。但這裡我們忽略了一個關鍵的問題,複雜度模型是基於每次相同的操作成本來考慮的。而資料庫實現比較複雜,一方面資料是儲存在磁碟上的,另外一方面為了提高效能,每次又可以把部分資料讀入記憶體來計算,因為我們知道訪問磁碟的成本大概是訪問記憶體的十萬倍左右,所以簡單的搜尋樹難以滿足複雜的應用場景。

  當一次IO時,不光把當前磁碟地址的資料,而是把相鄰的資料也都讀取到記憶體緩衝區內,因為區域性預讀性原理告訴我們,當計算機訪問一個地址的資料的時候,與其相鄰的資料也會很快被訪問到。每一次IO讀取的資料我們稱之為一頁(page)。

  每次查詢資料時把磁碟IO次數控制在一個很小的數量級,最好是常數數量級。那麼我們就想到如果一個高度可控的多路搜尋樹是否能滿足需求呢?就這樣,b+樹應運而生(B+樹是通過二叉查詢樹,再由平衡二叉樹,B樹演化而來)。

 

b+樹性質 1.索引欄位要儘量的小;2.索引的最左匹配特性

這種資料結構減少I/O次數

真實資料只存在葉子節點的磁碟塊的資料項;樹杈節點的資料象就是為了建資料結構而虛擬出的;

I/O固定在固定範圍,3次,它的高度決定的。

InnoDB儲存引擎表示索引組織表,即表中資料按照主鍵順序存放,建表的時候一定要建個主鍵,它會在你這個表裡邊找主鍵;

聚集索引與輔助索引

資料庫中的B+樹索引可以分為聚集索引(clustered index)和輔助索引(secondary index),

聚集索引與輔助索引相同的是:不管是聚集索引還是輔助索引,其內部都是B+樹的形式,即高度是平衡的,葉子結點存放著所有的資料。

聚集索引與輔助索引不同的是:葉子結點存放的是否是一整行的資訊