MySQL基本操作解析
一、数据库概述
二、MySQL下载与基本配置
三、基本SQL语句
四、库(database)操作详解
五、表(table)操作详解
六、数据(记录)操作详解
七、pymysql模块
八、视图、触发器、事务、存储过程、函数
一、数据库概述
什么是数据(what):
用于记录显示世界中的某种状态。
什么是记录(what):
就相当于文件中一行内容(抽取事物一系列典型的特征拼到一起)。
什么是表(what):
相当于一个文件。
什么是库(what):
相当于一个文件夹。
什么是数据库管理软件(what):
相当于一个套接字服务端,数据库中的数据按一定的数据模型组织、描述和储存,具有较小的冗余度、较高的数据独立性和易扩展性,并可为各种 用户共享。
什么是数据库服务器(what):
运行有数据库管理软件的计算机。
数据库本身就是一个C/S架构的套接字软件。
常见的数据库:
关系型:
mysql
mariadb
oracle
db2
sqlserver
非关系:
存取数据都是以key:value
mongodb
redis
memcache
二、MySQL下载与基本配置
1、Windows版本下载地址
https://www.mysql.com/downloads/
2、拷贝到存放路径解压即用
3、修改精简文件名
4、修改环境变量
将mysql路径添加到path下的环境变量(用;分割)
5、用管理员模式打开cmd.exe,通过cd命令切换到mysql路径(Windows下要加d)
6、创建my.ini修改配置,设置默认账号、默认密码及识别的字符编码。
#mysql5.5以上:修改方式有所改动
[mysqld] character-set-server=utf8 collation-server=utf8_general_ci [client] default-character-set=utf8 user='root' password='' [mysql] default-character-set=utf8 user='root' password=''
7、输入mysqld.exe --install,直接启动服务
8、进入services.msc找到MySQL启动服务
Tip:
【破解密码登录】
#1 关闭mysql #2 在cmd中执行:mysqld --skip-grant-tables #3 在cmd中执行:mysql #4 执行如下sql: update mysql.user set authentication_string=password('') where user = 'root'; flush privileges; #5 tskill mysqld #或taskkill -f /PID 7832 #6 重新启动mysql
[root@egon ~]# vim /etc/my.cnf #mysql主配置文件 [mysqld] skip-grant-table [root@egon ~]# systemctl restart mariadb [root@egon ~]# mysql MariaDB [(none)]> update mysql.user set password=password("123") where user="root" and host="localhost"; MariaDB [(none)]> flush privileges; MariaDB [(none)]> q [root@egon ~]# #打开/etc/my.cnf去掉skip-grant-table,然后重启 [root@egon ~]# systemctl restart mariadb [root@egon ~]# mysql -u root -p123 #以新密码登录
三、基本SQL语句
SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统,SQL语言由IBM开发。SQL语言分为3种类型: #1、DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER #2、DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT #3、DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
*****修改sql_mode模式*****
默认模式为非严格模式,对于某些不符合限制的内容系统不会报错,会自行处理。
严格模式在遇到不符合限制条件的语句会报错。
修改sql_mode为严格模式,必须重启客户端才能生效。
set global sql_mode="strict_trans_tables";
select @@sql_mode;
(一)库database(文件夹)
增:create database db1 charset utf8;
查:show databases;
改:alter database db1 charset latin1;
删: drop database db1;
(二)表table(文件)
*****先选择文件夹,也就是要操作的库*****
select database(); 查看当前所在的库
use db1;
增:
create table t1(id int,name char);
create table db1.t1(id int,name char);
create table t2(id int primary key auto_incremnt,name char(15)); # 限制id默认不能重复且自动排序
insert into t2(name) values
('egon'),
('lxx'),
('wxx'),
('axx');
删: drop table t1; #删除表 改: alter table t1 add age int; #增加字段 alter table t1 modify name char(15); #修改字段属性 alter table t1 change name NAME char(15); #修改字段属性及修改字段名 alter table t1 drop age; #删除字段 查: show tables; #查看库下有哪些表 show create table t1; #查看创建的表t1 desc t1; #查看表内属性设置
(三)记录(文件内容)
增: insert into t1(id,name) values (1,'egon'), (2,'lxx'), (3,'alex'); 删: delete from db1.t1 where id >= 2; # 删除某条记录 *****初始化表***** 前文添加表时使用到了primary及key auto_increment来设置不可重复且自动排序,如果用delete from db1.t1 where id >= 2;删除记录,会导致继续添加记录时,新的id从删除部分
继续计数。 可以使用truncate t2;进行初始化表 实际应用场景中,一般不建议删除记录,会在记录内添加一个状态来控制这条记录的状态。 改: update db1.t1 set name='lxx_dsb' where id=2; 查: select id from db1.t1; select id,name from t1; select name,id from t1; select * from t1; select * from t1 where id >= 2;
四、库(database)操作详解
(一)创建数据库
1.语法
CREATE DATABASE 数据库名 charset utf8;
2.命名规则
可以由字母、数字、下划线、@、#、$
区分大小写
唯一性
不能使用关键字如 create select
不能单独使用数字
最长128位
(二)相关操作
查看数据库
show databases;
show create database db1;
select database();
选择数据库
USE 数据库名
删除数据库
DROP DATABASE 数据库名;
修改数据库
alter database db1 charset utf8;
五、表(table)操作详解
(一)创建表
1.语法
create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件],
字段名3 类型[(宽度) 约束条件]
);
2.使用规则
1.同一张表中字段名不能相同 2.宽度与约束条件可选,字段名与类型是必须的 3.约束条件是在数据类型之外对字段附加的额外限制 4.最后一个字段之后不能加逗号
3.数据类型
①整型
整数类型:TINYINT SMALLINT MEDIUMINT INT BIGINT
作用:存储年龄,等级,id,各种号码等
#强调1:默认是有符号的 create table t3(x tinyint); create table t4(x tinyint unsigned); # 强调2:整型类型后面的宽度限制的根本不是存储宽度,限制的是显示宽度 create table t5(id int(1)); create table t6(id int(5));
②浮点型
定点数类型:DEC等同于DECIMAL
浮点类型:FLOAT DOUBLE
作用:存储薪资、身高、体重、体质参数等
====================================== #FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] 定义: 单精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。m最大值为255,d最大值为30 有符号: -3.402823466E+38 to -1.175494351E-38, 1.175494351E-38 to 3.402823466E+38 无符号: 1.175494351E-38 to 3.402823466E+38 精确度: **** 随着小数的增多,精度变得不准确 **** ====================================== #DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] 定义: 双精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。m最大值为255,d最大值为30 有符号: -1.7976931348623157E+308 to -2.2250738585072014E-308 2.2250738585072014E-308 to 1.7976931348623157E+308 无符号: 2.2250738585072014E-308 to 1.7976931348623157E+308 精确度: ****随着小数的增多,精度比float要高,但也会变得不准确 **** ====================================== decimal[(m[,d])] [unsigned] [zerofill] 定义: 准确的小数值,m是数字总个数(负号不算),d是小数点后个数。 m最大值为65,d最大值为30。 精确度: **** 随着小数的增多,精度始终准确 **** 对于精确数值计算时需要用此类型 decaimal能够存储精确值的原因在于其内部按照字符串存储。
float(255,30) double(255,30) decimal(65,30) create table t8(x float(255,30)); create table t9(x double(255,30)); create table t10(x decimal(65,30)); insert into t8 values(1.111111111111111111111111111111); insert into t9 values(1.111111111111111111111111111111); insert into t10 values(1.111111111111111111111111111111);
③日期类型
DATE TIME DATETIME TIMESTAMP YEAR
作用:存储用户注册时间,文章发布时间,员工入职时间,出生时间,过期时间等
YEAR YYYY(1901/2155) DATE YYYY-MM-DD(1000-01-01/9999-12-31) TIME HH:MM:SS('-838:59:59'/'838:59:59') 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 年某时)
year 1999 date 1999-11-11 time 08:30:00 datetime/timestamp 1999-11-11 08:30:00 create table student( id int primary key auto_increment, name char(16), born_year year, birth date, class_time time, reg_time datetime ); insert into student(name,born_year,birth,class_time,reg_time) values ('egon1',now(),now(),now(),now()); insert into student(name,born_year,birth,class_time,reg_time) values ('egon1',2000,20001111,now(),now()); insert into student(name,born_year,birth,class_time,reg_time) values ('egon1',2000,'2000-11-11',083000,now()); insert into student(name,born_year,birth,class_time,reg_time) values ('egon1',2000,'2000-11-11',"08:30:00",20171111111111); insert into student(name,born_year,birth,class_time,reg_time) values ('egon1',2000,'2000-11-11',"08:30:00","2017-11-11 11:11:11"); create table t11(x timestamp); create table t12(x datetime not null default now());
============注意啦,注意啦,注意啦=========== 1. 单独插入时间时,需要以字符串的形式,按照对应的格式插入 2. 插入年份时,尽量使用4位值 3. 插入两位年份时,<=69,以20开头,比如50, 结果2050 >=70,以19开头,比如71,结果1971
④字符类型
*****注意:宽度指限制的是字符个数*****
char类型:定长,简单粗暴,浪费空间,存取速度快
char:定长
char(5)
varchar类型:变长,精准,节省空间,存取速度慢
varchar:变长
varchar(5)
相同点:
宽度指的都是最大存储的字符个数,超过了都无法正常存储
不同点:
char(5):
'm'--->'m '5个字符
varchar(5)
'm'--->'m'1个字符
*****注意*****
mysql在查询时针对where 字段="值 "会忽略掉右面的空格,即where 字段="值"
如果时like模糊匹配就不会忽略右面的空格了
*****存储方式*****
char(5)
egon |axx |lxx |fm |
varchar(5)
1bytes+egon|1bytes+axx|1bytes+lxx|1bytes+fm|
⑤枚举与集合类型
字段的值只能在给定范围中选择,如单选框,多选框
enum 单选 只能在给定的范围内选一个值,如性别 sex 男male/女female
set 多选 在给定的范围内可以选择一个或一个以上的值(爱好1,爱好2,爱好3...)
枚举类型(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');
4.完整性约束
约束条件与数据类型的宽度一样,都是可选参数
作用:用于保证数据的完整性和一致性
主要分为:
PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录
FOREIGN KEY (FK) 标识该字段为该表的外键
NOT NULL 标识该字段不能为空
UNIQUE KEY (UK) 标识该字段的值是唯一的
AUTO_INCREMENT 标识该字段的值自动增长(整数类型,而且为主键)
DEFAULT 为该字段设置默认值
UNSIGNED 无符号
ZEROFILL 使用0填充
说明:
1. 是否允许为空,默认NULL,可设置NOT NULL,字段不允许为空,必须赋值 2. 字段是否有默认值,缺省的默认值是NULL,如果插入记录时不给字段赋值,此字段使用默认值 sex enum('male','female') not null default 'male' age int unsigned NOT NULL default 20 必须为正值(无符号) 不允许为空 默认是20 3. 是否是key 主键 primary key 外键 foreign key 索引 (index,unique...)
①primary key
站在约束角度看primary key=not null unique,不能为空且唯一
以后但凡建表,必须注意:
1、必须有且只有一个主键
2、通常是id字段被设置为主键
create table t5(
id int primary key auto_increment
);
②foreign key
限制关联表某一个字段的值必是来自于被关联表的一个字段的。
# foreign key注意: # 1、被关联的字段必须是一个key,通常是id字段 # 2、创建表时:必须先建立被关联的表,才能建立关联表 create table dep( id int primary key auto_increment, dname varchar(20), info varchar(50) ); create table emp( id int primary key auto_increment, name varchar(15), age int, dep_id int, foreign key(dep_id) references dep(id) on update cascade on delete cascade ); # 3、插入记录时:必须先往被关联的表插入记录,才能往关联表中插入记录 insert into dep(dname,info) values ('IT','技术能力有限部门xxx'), ('Sale','文化程度不高'), ('HR','招不到人部门'); insert into emp(name,age,dep_id) values ('egon',18,1), ('alex',28,2), ('wsj',38,2), ('lxx',30,1), ('xiaohou',18,3); ps:删除时:应该先删除关联表emp中的记录,再删除被关联表对应的记录
找表关系诀窍:
emp dep #1、先站在左表的角度:去找左表emp的多条记录能否对应右表dep的一条记录 翻译:多个员工能否属于一个部门 #2、然后站在右表的角度:去找右表dep的多条记录能否对应左表emp的一条记录 翻译:多个部门能否拥有同一名员工
# 多对一:结果的判断 #1、如果只有单向的多对一成立,那么最终的关系就是多对一 #2、在emp表新增一个字段dep_id, 该字段外键关联dep(id)
# 多对多:结果的判断 #1、双向的多对一就是多对多 #2、需要建立第三张表,有一个字段值fk左表,一个字段的值fk右表 create table author( id int primary key auto_increment, name varchar(16), age int ); create table book( id int primary key auto_increment, bname varchar(20), price int ); create table author2book( id int primary key auto_increment, author_id int, book_id int, foreign key(author_id) references author(id) on update cascade on delete cascade, foreign key(book_id) references book(id) on update cascade on delete cascade );
# 一对一:无需参考窍门,左表的一条数据唯一对应右表的一条记录 fk+unique
③not full
是否可空,null表示空,非字符串
not null - 不可空
null - 可空
默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值
create table tb1(
nid int not null defalut 2,
num int not null
)
create table t1( id int primary key auto_increment, name varchar(16) not null, sex enum('male','female') not null default 'male' ); insert into t1(name) values('egon'),('lxx'),('alex');
④unique key
约束数值唯一性
方法一:
create table t2(x int unique);
方法二:
create table t3( x int, y varchar(5), unique key(x) );
方法三:constraint可定义联合唯一的key名,unique key(字段名1,字段名2)代表设置两个字段联合唯一
create table service( ip varchar(15), port int, unique key(ip,port) ); insert into service values ('1.1.1.1',3306), ('1.1.1.1',3306);
方法四:not null+unique = primary
mysql> create table t1(id int not null unique); Query OK, 0 rows affected (0.02 sec) mysql> desc t1; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | +-------+---------+------+-----+---------+-------+ row in set (0.00 sec) not null+unique的化学反应
⑤auto_increment
约束字段为自动增长,被约束的字段必须同时被key约束。
create table t2(id int primary key auto_incremnt,name char(15)); insert into t2(name) values ('egon'), ('lxx'), ('wxx'), ('axx');
⑥default
设置默认值
create table t1( id int primary key auto_increment, name varchar(16) not null, sex enum('male','female') not null default 'male' ); insert into t1(name) values('egon'),('lxx'),('alex');
(二)修改表
语法: 1. 修改表名 ALTER TABLE 表名 RENAME 新表名; 2. 增加字段 ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…], ADD 字段名 数据类型 [完整性约束条件…]; ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…] FIRST; ALTER TABLE 表名 ADD 字段名 数据类型 [完整性约束条件…] AFTER 字段名; 3. 删除字段 ALTER TABLE 表名 DROP 字段名; 4. 修改字段 ALTER TABLE 表名 MODIFY 字段名 数据类型 [完整性约束条件…]; ALTER TABLE 表名 CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…]; ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
(三)复制表
复制表结构+记录 (key不会复制: 主键、外键和索引) mysql> create table new_service select * from service; 只复制表结构 mysql> select * from service where 1=2; //条件为假,查不到任何记录 Empty set (0.00 sec) mysql> create table new1_service select * from service where 1=2; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> create table t4 like employees;
(四)删除表
DROP TABLE 表名;
六、数据(记录)操作详解
(一)插入数据insert
1. 插入完整数据(顺序插入) 语法一: INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n); 语法二: INSERT INTO 表名 VALUES (值1,值2,值3…值n); 2. 指定字段插入数据 语法: INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…); 3. 插入多条记录 语法: INSERT INTO 表名 VALUES (值1,值2,值3…值n), (值1,值2,值3…值n), (值1,值2,值3…值n); 4. 插入查询结果 语法: INSERT INTO 表名(字段1,字段2,字段3…字段n) SELECT (字段1,字段2,字段3…字段n) FROM 表2 WHERE …;
(二)更新数据update
语法: UPDATE 表名 SET 字段1=值1, 字段2=值2, WHERE CONDITION; 示例: UPDATE mysql.user SET password=password(‘123’) where user=’root’ and host=’localhost’;
(三)删除数据delete
语法: DELETE FROM 表名 WHERE CONITION; 示例: DELETE FROM mysql.user WHERE password=’’; 练习: 更新MySQL root用户密码为mysql123 删除除从本地登录的root用户以外的所有用户
(四)查询数据select
1.单表查询
a)语法
SELECT 字段1,字段2... FROM 表名
WHERE 条件
GROUP BY field
HAVING 筛选
ORDER BY field
LIMIT 限制条数
b)关键字执行顺序
重点中的重点:关键字的执行优先级 from where group by having select distinct order by limit
c)简单查询
company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职日期 hire_date date 岗位 post varchar 职位描述 post_comment varchar 薪水 salary double 办公室 office int 部门编号 depart_id int #创建表 create table employee( id int not null unique auto_increment, name varchar(20) not null, sex enum('male','female') not null default 'male', #大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, #一个部门一个屋子 depart_id int ); #查看表结构 mysql> desc employee; +--------------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(3) unsigned | NO | | 28 | | | hire_date | date | NO | | NULL | | | post | varchar(50) | YES | | NULL | | | post_comment | varchar(100) | YES | | NULL | | | salary | double(15,2) | YES | | NULL | | | office | int(11) | YES | | NULL | | | depart_id | int(11) | YES | | NULL | | +--------------+-----------------------+------+-----+---------+----------------+ #插入记录 #三个部门:教学,销售,运营 insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values ('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部 ('alex','male',78,'20150302','teacher',1000000.31,401,1), ('wupeiqi','male',81,'20130305','teacher',8300,401,1), ('yuanhao','male',73,'20140701','teacher',3500,401,1), ('liwenzhou','male',28,'20121101','teacher',2100,401,1), ('jingliyang','female',18,'20110211','teacher',9000,401,1), ('jinxin','male',18,'19000301','teacher',30000,401,1), ('成龙','male',48,'20101111','teacher',10000,401,1), ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门 ('丫丫','female',38,'20101101','sale',2000.35,402,2), ('丁丁','female',18,'20110312','sale',1000.37,402,2), ('星星','female',18,'20160513','sale',3000.29,402,2), ('格格','female',28,'20170127','sale',4000.33,402,2), ('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门 ('程咬金','male',18,'19970312','operation',20000,403,3), ('程咬银','female',18,'20130311','operation',19000,403,3), ('程咬铜','male',18,'20150411','operation',18000,403,3), ('程咬铁','female',18,'20140512','operation',17000,403,3) ; #ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk
#简单查询 SELECT id,name,sex,age,hire_date,post,post_comment,salary,office,depart_id FROM employee; SELECT * FROM employee; SELECT name,salary FROM employee; #避免重复DISTINCT SELECT DISTINCT post FROM employee; #通过四则运算查询 SELECT name, salary*12 FROM employee; SELECT name, salary*12 AS Annual_salary FROM employee; SELECT name, salary*12 Annual_salary FROM employee; #定义显示格式 CONCAT() 函数用于连接字符串 SELECT CONCAT('姓名: ',name,' 年薪: ', salary*12) AS Annual_salary FROM employee; CONCAT_WS() 第一个参数为分隔符 SELECT CONCAT_WS(':',name,salary*12) AS Annual_salary FROM employee; 结合CASE语句: SELECT ( CASE WHEN NAME = 'egon' THEN NAME WHEN NAME = 'alex' THEN CONCAT(name,'_BIGSB') ELSE concat(NAME, 'SB') END ) as new_name FROM emp;
d)where约束
where字句中可以使用:
1. 比较运算符:> < >= <= <> !=
2. between 80 and 100 值在10到20之间
3. in(80,90,100) 值是10或20或30
4. like 'egon%'
pattern可以是%或_,
%表示任意多字符
_表示一个字符
5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
#1:单条件查询 SELECT name FROM employee WHERE post='sale'; #2:多条件查询 SELECT name,salary FROM employee WHERE post='teacher' AND salary>10000; #3:关键字BETWEEN AND SELECT name,salary FROM employee WHERE salary BETWEEN 10000 AND 20000; SELECT name,salary FROM employee WHERE salary NOT BETWEEN 10000 AND 20000; #4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS) SELECT name,post_comment FROM employee WHERE post_comment IS NULL; SELECT name,post_comment FROM employee WHERE post_comment IS NOT NULL; SELECT name,post_comment FROM employee WHERE post_comment=''; 注意''是空字符串,不是null ps: 执行 update employee set post_comment='' where id=2; 再用上条查看,就会有结果了 #5:关键字IN集合查询 SELECT name,salary FROM employee WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ; SELECT name,salary FROM employee WHERE salary IN (3000,3500,4000,9000) ; SELECT name,salary FROM employee WHERE salary NOT IN (3000,3500,4000,9000) ; #6:关键字LIKE模糊查询 通配符’%’ SELECT * FROM employee WHERE name LIKE 'eg%'; 通配符’_’ SELECT * FROM employee WHERE name LIKE 'al__';
e)group by分组查询
什么是分组(what):
按照所有记录相同的部分进行归类,一定区分度低的字段。
为什么要分组(why):
当我们要以组为单位进行统计时就必须分组,分组的目的是为了以组为单位进行统计的,再去考虑单条记录毫无意义。
聚合函数:
max、min、avg、sum、count
#强调:聚合函数聚合的是组的内容,若是没有分组,则默认一组 示例: SELECT COUNT(*) FROM employee; SELECT COUNT(*) FROM employee WHERE depart_id=1; SELECT MAX(salary) FROM employee; SELECT MIN(salary) FROM employee; SELECT AVG(salary) FROM employee; SELECT SUM(salary) FROM employee; SELECT SUM(salary) FROM employee WHERE depart_id=3;
注意:
①分组之后,只能查到分组的字段以及组内多条记录聚合的成果
②分组是在where之后发生的
先设置模式:
set global sql_mode="strict_trans_tables,only_full_group_by";
语法:
单独使用GROUP BY关键字分组 SELECT post FROM employee GROUP BY post; 注意:我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数 GROUP BY关键字和GROUP_CONCAT()函数一起使用 SELECT post,GROUP_CONCAT(name) FROM employee GROUP BY post;#按照岗位分组,并查看组内成员名 SELECT post,GROUP_CONCAT(name) as emp_members FROM employee GROUP BY post; GROUP BY与聚合函数一起使用 select post,count(id) as count from employee group by post;#按照岗位分组,并查看每个组有多少人
(f)having过滤条件
注意:
①where是在分组之前的过滤,即在分组之前做了一次整体性的筛选
②having是在分组之后的过滤,即在分组之后专门针对聚合的结果进行进一步的筛选
mysql> select * from emp having salary > 100000; ERROR 1463 (42000): Non-grouping field 'salary' is used in HAVING clause mysql> select post,group_concat(name) from emp group by post having salary > 10000;#错误,分组后无法直接取到salary字段 ERROR 1054 (42S22): Unknown column 'salary' in 'having clause' mysql> select post,group_concat(name) from emp group by post having avg(salary) > 10000; +-----------+-------------------------------------------------------+ | post | group_concat(name) | +-----------+-------------------------------------------------------+ | operation | 程咬铁,程咬铜,程咬银,程咬金,张野 | | teacher | 成龙,jinxin,jingliyang,liwenzhou,yuanhao,wupeiqi,alex | +-----------+-------------------------------------------------------+ 2 rows in set (0.00 sec)
(g)order by 排序查询
按单列排序 SELECT * FROM employee ORDER BY salary; SELECT * FROM employee ORDER BY salary ASC; SELECT * FROM employee ORDER BY salary DESC; 按多列排序:先按照age排序,如果年纪相同,则按照薪资排序 SELECT * from employee ORDER BY age, salary DESC;
(h)limit限制查询记录数
SELECT * FROM employee ORDER BY salary DESC LIMIT 3; #默认初始位置为0 SELECT * FROM employee ORDER BY salary DESC LIMIT 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5条 SELECT * FROM employee ORDER BY salary DESC LIMIT 5,5; #从第5开始,即先查询出第6条,然后包含这一条在内往后查5条
(i)正则表达式查询
SELECT * FROM employee WHERE name REGEXP '^ale'; SELECT * FROM employee WHERE name REGEXP 'on$'; SELECT * FROM employee WHERE name REGEXP 'm{2}'; 小结:对字符串匹配的方式 WHERE name = 'egon'; WHERE name LIKE 'yua%'; WHERE name REGEXP 'on$';
2.多表查询
#建表 create table department( id int, name varchar(20) ); create table employee( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male', age int, dep_id int ); #插入数据 insert into department values (200,'技术'), (201,'人力资源'), (202,'销售'), (203,'运营'); insert into employee(name,sex,age,dep_id) values ('egon','male',18,200), ('alex','female',48,201), ('wupeiqi','male',38,201), ('yuanhao','female',28,202), ('liwenzhou','male',18,200), ('jingliyang','female',18,204) ; #查看表结构和数据 mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ mysql> desc employee; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | | NULL | | +--------+-----------------------+------+-----+---------+----------------+ mysql> select * from department; +------+--------------+ | id | name | +------+--------------+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +------+--------------+ mysql> select * from employee; +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+ 表department与employee
(一)笛卡尔积
select * from emp,dep; select * from emp,dep where emp.dep_id = dep.id; select * from emp,dep where emp.dep_id = dep.id and dep.name = "技术";
(二)内连接:只取两张表有对应关系的记录
select * from emp inner join dep on emp.dep_id = dep.id; select * from emp inner join dep on emp.dep_id = dep.id where dep.name = "技术";
(三)左连接: 在内连接的基础上保留左表没有对应关系的记录
select * from emp left join dep on emp.dep_id = dep.id;
(四)右连接: 在内连接的基础上保留右表没有对应关系的记录
select * from emp right join dep on emp.dep_id = dep.id;
(五)全连接:在内连接的基础上保留左、右面表没有对应关系的的记录
select * from emp left join dep on emp.dep_id = dep.id union select * from emp right join dep on emp.dep_id = dep.id;
(六)子查询
#1:子查询是将一个查询语句嵌套在另一个查询语句中。 #2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。 #3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字 #4:还可以包含比较运算符:= 、 !=、> 、<等
#查询平均年龄在25岁以上的部门名 select id,name from department where id in (select dep_id from employee group by dep_id having avg(age) > 25); #查看技术部员工姓名 select name from employee where dep_id in (select id from department where name='技术'); #查看不足1人的部门名(子查询得到的是有人的部门id) select name from department where id not in (select distinct dep_id from employee);
#比较运算符:=、!=、>、>=、<、<=、<> #查询大于所有人平均年龄的员工名与年龄 mysql> select name,age from emp where age > (select avg(age) from emp); +---------+------+ | name | age | +---------+------+ | alex | 48 | | wupeiqi | 38 | +---------+------+ rows in set (0.00 sec) #查询大于部门内平均年龄的员工名、年龄 select t1.name,t1.age from emp t1 inner join (select dep_id,avg(age) avg_age from emp group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age;
#department表中存在dept_id=203,Ture mysql> select * from employee -> where exists -> (select id from department where id=200); +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+ #department表中存在dept_id=205,False mysql> select * from employee -> where exists -> (select id from department where id=204); Empty set (0.00 sec)
七、pymysql模块
#安装 pip3 install pymysql
(一)创建连接,创建游标,执行sql,关闭游标
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('登录失败')
(二)execute()之sql注入
最后那一个空格,在一条sql语句中如果遇到select * from t1 where id > 3 -- and name='egon';则--之后的条件被注释掉了 #1、sql注入之:用户存在,绕过密码 egon' -- 任意字符 #2、sql注入之:用户不存在,绕过用户与密码 xxx' or 1=1 -- 任意字符
解决方法:
解决 sql注入问题 pip3 install pymysql import pymysql client=pymysql.connect( host='127.0.0.1', port=3306, user='root', password='egon123', database='db6', charset='utf8' ) cursor=client.cursor() #查询 inp_user=input('输入账号名: ').strip() inp_pwd=input('输入密码: ').strip() sql='select id from user where name = %s and pwd = %s;' rows=cursor.execute(sql,(inp_user,inp_pwd)) if rows: print('