第八章| 3. MyAQL数据库|Navicat工具与pymysql模块 | 内置功能 | 索引原理

1、Navicat工具与pymysql模块

在生产环境中操作MySQL数据库还是推荐使用命令行工具mysql,但在我们自己开发测试时,可以使用可视化工具Navicat,以图形界面的形式操作MySQL数据库
掌握:
#. 测试+链接数据库
#. 新建库
#. 新建表,新增字段+类型+约束
#. 设计表:外键
#. 新建查询
#. 备份库/表 #注意:
批量加注释:ctrl+?键
批量去注释:ctrl+shift+?键

第八章| 3. MyAQL数据库|Navicat工具与pymysql模块 | 内置功能 | 索引原理

之前我们都是通过MySQL自带的命令行客户端工具mysql来操作数据库,那如何在python程序中操作数据库呢?这就用到了pymysql模块,该模块本质就是一个套接字客户端软件,使用前需要事先安装   pip3 install pymysql

准备账号、表

用cmd授权一个账号

C:\Users\Administrator>mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is
Server version: 5.6. MySQL Community Server (GPL) Copyright (c) , , Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> grant all on *.* to 'root'@'%' identified by '';
Query OK, rows affected (0.07 sec) mysql> flush privileges;
Query OK, rows affected (0.12 sec)

查看IP地址:

在管理员权限下运行cmd,输入ipconfig

IPv4 地址 . . . . . . . . . . . . : 192.168.1.123

import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip() # 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
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('登录失败')

mysql语句中 -- xfjl ,--+空格后边的都给你注释掉了

import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip() # 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
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('登录失败') 打印: #两种执行的错误
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 = -- hhhhhaaa" and pwd=""
登录成功

改正:

import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip() # 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
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('登录失败')

增加

import pymysql

# 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
db='db10',
charset='utf8'
) # 拿游标
cursor=conn.cursor() # 执行sql
# 增、删、改 对数据的变动
sql='insert into userinfo(user,pwd) values(%s,%s)'
rows=cursor.execute(sql,('wxx',''))
print(rows) conn.commit() #必须加上这个
# 关闭
cursor.close()
conn.close() 打印:
#、增删改
import pymysql # 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
db='db10',
charset='utf8'
) # 拿游标
cursor=conn.cursor() # 执行sql
# 增、删、改 对数据的变动
sql='insert into userinfo(user,pwd) values(%s,%s)'
# rows=cursor.execute(sql,('wxx',''))
# print(rows)
rows=cursor.executemany(sql,[('yxx',''),('egon1',''),('egon2','')]) #可以插入多条
print(rows) conn.commit() #必须加上这个
# 关闭
cursor.close()
conn.close() 打印
#、查询
import pymysql
# # 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
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()) #指定取的个数,以列表的形式 #print(cursor.fetchall()) #拿出所有,列表的形式
# print(cursor.fetchall()) cursor.scroll(,mode='absolute') #移动光标 相对绝对位置移动,从头数3个开始取出来1个,结果是第4个
#print(cursor.fetchone())
cursor.scroll(,mode='relative') # 相对当前位置移动 往后跳2位
print(cursor.fetchone())
# 关闭
cursor.close()
conn.close() 打印: {'id': , 'user': 'egon2', 'pwd': ''}
import pymysql
#
# # 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
db='db10',
charset='utf8'
)
#
# # 拿游标
cursor=conn.cursor() sql='insert into userinfo(user,pwd) values(%s,%s)' rows=cursor.executemany(sql,[('egon3',''),('egon4',''),('egon5','')])
print(cursor.lastrowid) #插入之前光标走到哪里了
#
conn.commit() #必须加上这个
# 关闭
cursor.close()
conn.close() 打印:

涉及数据库的操作的,先要编写好数据,然后基于pymysql模块帮我把sql语句提交给mysql服户端,执行完之后把结果再返回到应用程序中再做进一步的处理;将应用程序的开发与数据库的开发结合

2、mysql内置函数功能

  视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,可以将该结果集当做表来使用。

  使用视图我们可以把查询过程中的临时表摘出来,用视图去实现,这样以后再想操作该临时表的数据时就无需重写复杂的sql了,直接去视图中查找即可,但视图有明显地效率问题,并且视图是存放在数据库中的,如果我们程序中使用的sql过分依赖数据库中的视图,即强耦合,那就意味着扩展sql极为不便,因此并不推荐使用

  视图 只有表结构frm,没有数据,因为是查出来的虚拟表;不用重复写,但是不建议使用,如果有好多个视图,要找到所有的视图给它修改很麻烦;

mysql> use db7;
Database changed
mysql> select * from course;
+-----+--------+------------+
| cid | cname | teacher_id |
+-----+--------+------------+
| | 生物 | |
| | 物理 | |
| | 体育 | |
| | 美术 | |
+-----+--------+------------+
rows in set (0.00 sec) mysql> select * from teacher;
+-----+-----------------+
| tid | tname |
+-----+-----------------+
| | 张磊老师 |
| | 李平老师 |
| | 刘海燕老师 |
| | 朱云海老师 |
| | 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 |
+-----+--------+------------+-----+-----------------+
| | 生物 | | | 张磊老师 |
| | 物理 | | | 李平老师 |
| | 美术 | | | 李平老师 |
| | 体育 | | | 刘海燕老师 |
+-----+--------+------------+-----+-----------------+
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, rows affected (0.20 sec) mysql> show tables;
+----------------+
| Tables_in_db7 |
+----------------+
| course |
| course2teacher |
| teacher |
+----------------+
rows in set (0.00 sec) mysql>

触发器

使用触发器可以定制用户对表进行【增、删、改】操作时前后的行为,注意:没有查询

mysql> create database db11;
Query OK, row affected (0.00 sec) mysql> use db11;
Database changed
mysql> CREATE TABLE cmd (
-> id INT PRIMARY KEY auto_increment,
-> USER CHAR (),
-> priv CHAR (),
-> cmd CHAR (),
-> sub_time datetime, #提交时间
-> success enum ('yes', 'no') #0代表执行失败
-> );
Query OK, rows affected (0.77 sec) mysql>
mysql> CREATE TABLE errlog (
-> id INT PRIMARY KEY auto_increment,
-> err_cmd CHAR (),
-> err_time datetime
-> );
Query OK, 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, rows affected (0.34 sec)
mysql> delimiter ;
mysql>
mysql>
mysql>#往cmd中插入记录,触动触发器,根据IF条件决定是否插入错误日志
mysql> INSERT INTO cmd (
-> USER,
-> priv,
-> cmd,
-> sub_time,
-> success
-> )
-> VALUES
-> ('egon','','ls -l /etc',NOW(),'yes'),
-> ('egon','','cat /etc/passwd',NOW(),'no'),
-> ('egon','','useradd xxx',NOW(),'no'),
-> ('egon','','ps aux',NOW(),'yes');
Query OK, rows affected (0.43 sec)
Records: Duplicates: Warnings: mysql> select * from cmd; +----+------+------+-----------------+---------------------+---------+
| id | USER | priv | cmd | sub_time | success |
+----+------+------+-----------------+---------------------+---------+
| | egon | | ls -l /etc | -- :: | yes |
| | egon | | cat /etc/passwd | -- :: | no |
| | egon | | useradd xxx | -- :: | no |
| | egon | | ps aux | -- :: | yes |
+----+------+------+-----------------+---------------------+---------+
rows in set (0.00 sec) mysql> select * from errlog; #查询错误日志发现有两条
+----+-----------------+---------------------+
| id | err_cmd | err_time |
+----+-----------------+---------------------+
| | cat /etc/passwd | -- :: |
| | useradd xxx | -- :: |
+----+-----------------+---------------------+
rows in set (0.00 sec)

存储过程

把mysql处理好的数据给封装好,一个接口名,应用程序可以直接调用接口,这个接口就叫储存过程。是mysql内置功能的一系列总和;

存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql

使用存储过程的优点:

1. 用于替代程序写的SQL语句,实现程序与sql解耦

2. 基于网络传输,传别名的数据量小,而直接传sql数据量大

使用存储过程的缺点:

1. 程序员扩展功能不方便

程序与数据库结合使用的三种方式:

#方式一:
MySQL:存储过程
程序:调用存储过程
#方式二:
MySQL:
程序:纯SQL语句
#方式三:
MySQL:
程序:类和对象,即ORM(本质还是纯SQL语句)

创建简单的存储过程:

#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, 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)
    # MySQL中调用
call p1();
mysql> call p1();
+-----+-----------------+
| tid | tname |
+-----+-----------------+
| | 张磊老师 |
| | 李平老师 |
| | 刘海燕老师 |
| | 朱云海老师 |
| | alex |
+-----+-----------------+
rows in set (0.00 sec) Query OK, rows affected (0.01 sec)
    # Python中调用
cursor.callproc('p1') #调用存储过程
import pymysql

# 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
db='db7',
charset='utf8'
) # 拿游标
cursor=conn.cursor() # 执行sql
cursor.callproc('p1') #只是执行
print(cursor.fetchall()) 打印
((, '张磊老师'), (, '李平老师'), (, '刘海燕老师'), (, '朱云海老师'), (, 'alex'))

#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 = ;
-> END //
Query OK, rows affected (0.06 sec) mysql> delimiter ; mysql> set @x=;
Query OK, rows affected (0.00 sec) mysql> call p2(,,@x);
+-----+-----------------+
| tid | tname |
+-----+-----------------+
| | 刘海燕老师 |
+-----+-----------------+
row in set (0.00 sec) Query OK, rows affected (0.01 sec) mysql> select @x;
+------+
| @x |
+------+
| |
+------+
row in set (0.00 sec)
import pymysql

# 建立链接
conn=pymysql.connect(
host='192.168.1.123',
port=,
user='root',
password='',
db='db7',
charset='utf8'
) # 拿游标
cursor=conn.cursor() #
cursor.execute('select @_p2_2')
print(cursor.fetchone()) # 关闭
cursor.close()
conn.close() 打印
(1, )

应用程序与数据库结合使用

方式一: (很少用,部门之间沟通效率不高;优点很好解开了耦合,效率最高)
Python:调用存储过程
MySQL:编写存储过程 方式二:
Python:编写纯生SQL (可维护性好,都是开发人员写的,)
MySQL: 方式三:
Python:ORM->纯生SQL (开发效率高,可维护性高,用类,ORM框架)
MySQL:

事务

同时成功同时失败;

事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

mysql> create table user(
-> id int primary key auto_increment,
-> name char(),
-> balance int
-> );
Query OK, rows affected (1.98 sec) mysql>
mysql> insert into user(name,balance)
-> values
-> ('wsb',),
-> ('egon',),
-> ('ysb',);
Query OK, rows affected (0.50 sec)
Records: Duplicates: Warnings: mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| | wsb | |
| | egon | |
| | ysb | |
+----+------+---------+
rows in set (0.00 sec)

#原子操作
mysql> start transaction;
Query OK, rows affected (0.05 sec) mysql> update user set balance= where name='wsb'; #买支付100元
Query OK, row affected (0.11 sec)
Rows matched: Changed: Warnings: mysql> update user set balance= where name='egon'; #中介拿走10元
Query OK, row affected (0.00 sec)
Rows matched: Changed: Warnings: mysql> update user set balance= where name='ysb'; #卖家拿到90元
Query OK, row affected (0.00 sec)
Rows matched: Changed: Warnings: mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| | wsb | |
| | egon | |
| | ysb | |
+----+------+---------+
rows in set (0.00 sec) mysql> commit;
Query OK, rows affected (0.16 sec) mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| | wsb | |
| | egon | |
| | ysb | |
+----+------+---------+
rows in set (0.00 sec) mysql> rollback; #出现异常就回滚到初始状态
Query OK, rows affected (0.00 sec) mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| | wsb | |
| | egon | |
| | ysb | |
+----+------+---------+
rows in set (0.00 sec)

函数与流程控制

函数

一、数学函数
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',,); 表示将 a 由16进制转换为2进制字符串表示 FORMAT(X,D)
将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 , 则返回结果不带有小数点,或不含小数部分。
例如:
SELECT FORMAT(12332.1,); 结果为: '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',);
-> 'ratically' mysql> SELECT SUBSTRING('foobarbar' FROM );
-> 'barbar' mysql> SELECT SUBSTRING('Quadratically',,);
-> 'ratica' mysql> SELECT SUBSTRING('Sakila', -);
-> 'ila' mysql> SELECT SUBSTRING('Sakila', -, );
-> 'aki' mysql> SELECT SUBSTRING('Sakila' FROM - FOR );
-> 'ki' 四、日期和时间函数
CURDATE()或CURRENT_DATE() 返回当前的日期
CURTIME()或CURRENT_TIME() 返回当前的时间
DAYOFWEEK(date) 返回date所代表的一星期中的第几天(~)
DAYOFMONTH(date) 返回date是一个月的第几天(~)
DAYOFYEAR(date) 返回date是一年的第几天(~)
DAYNAME(date) 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt) 根据指定的fmt格式,格式化UNIX时间戳ts
HOUR(time) 返回time的小时值(~)
MINUTE(time) 返回time的分钟值(~)
MONTH(date) 返回date的月份值(~)
MONTHNAME(date) 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW() 返回当前的日期和时间
QUARTER(date) 返回date在一年中的季度(~),如SELECT QUARTER(CURRENT_DATE);
WEEK(date) 返回日期date为一年中第几周(~)
YEAR(date) 返回日期date的年份(~) 重点:
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');
-> '' 五、加密函数
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
mysql> CREATE TABLE blog (
-> id INT PRIMARY KEY auto_increment,
-> NAME CHAR (),
-> sub_time datetime
-> );
Query OK, 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, rows affected (0.14 sec)
Records: Duplicates: Warnings: mysql> SELECT DATE_FORMAT(sub_time,'%Y-%m'),COUNT() FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y-%m');
+-------------------------------+----------+
| DATE_FORMAT(sub_time,'%Y-%m') | COUNT() |
+-------------------------------+----------+
| - | |
| - | |
| - | |
+-------------------------------+----------+
rows in set (0.22 sec) mysql>

流程控制

delimiter //
CREATE PROCEDURE proc_if ()
BEGIN declare i int default ;
if i = THEN
SELECT ;
ELSEIF i = THEN
SELECT ;
ELSE
SELECT ;
END IF; END //
delimiter ; if条件语句

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次数

第八章| 3. MyAQL数据库|Navicat工具与pymysql模块 | 内置功能 | 索引原理

真实数据只存在叶子节点的磁盘块的数据项;树杈节点的数据象就是为了建数据结构而虚拟出的;

I/O固定在固定范围,3次,它的高度决定的。

InnoDB存储引擎表示索引组织表,即表中数据按照主键顺序存放,建表的时候一定要建个主键,它会在你这个表里边找主键;

聚集索引与辅助索引

数据库中的B+树索引可以分为聚集索引(clustered index)和辅助索引(secondary index),

聚集索引与辅助索引相同的是:不管是聚集索引还是辅助索引,其内部都是B+树的形式,即高度是平衡的,叶子结点存放着所有的数据。

聚集索引与辅助索引不同的是:叶子结点存放的是否是一整行的信息

上一篇:通用mapper的使用


下一篇:Navicat工具、pymysql模块 sql注入