1,简介
数据库,简而言之就是存储数据的仓库,可以按照一定的数据结构存储管理大量的数据及数据与数据之间的关系,它本质上是一种信息管理系统。数据库根据存储采用的数据结构的不同可以分为许多种,其中常见的有层次式数据库、网络式数据库、关系型数据库。其中关系型数据库占据着市场的主流。
关系型数据库是建立在关系模型基础上的数据库。这种定义听起来十分抽象,这里我们不深入讨论什么叫做“关系模型”--大学计算机专业专门有一门课叫“离散数学”专门讨论过关系模型 --,只是简单的表述为 利用表来存储数据,用表和表之间的关系保存数据之间的关系的数据库称为关系型数据库,这个定义不太严谨,但是更好理解。
2.mysql支持的七种表数据类型
截至目前,MySQL一共向用户提供了包括DBD、HEAP、ISAM、MERGE、MyIAS、InnoDB以及Gemeni这7种Mysql表类型。其中DBD、InnoDB属于事务安全类表,而其他属于事务非安全类表。
DBD
Berkeley DB(DBD)表是支持事务处理的表,由Sleepycat软件公司开发。它提供MySQL用户期待已久的功能--事务控制。事务控制在任何数据库系统中都是一个极有价值的功能,因为它们确保一组命令能成功地执行或回滚。
HEAP
HEAP表是MySQL中存取数据最快的表。这是因为他们使用存储在动态内存中的一个散列索引,不过如果MySQL或服务器崩溃,这些内存数据将会丢失。
ISAM
ISAM表是早期MySQL版本的缺省表类型,直到MyIASM开发出来。建议不要再使用它。
MERGE
MERGE是一个有趣的新类型,在3.23.25之后出现。一个MERGE表实际上是又一个MyISAM表的集合,合并而成的一个表,主要是为了效率的考虑,因为这样不仅仅可以提高速度、搜索效率、修复效率而且还节省了磁盘空间。
MyIASM
MyIASM基于了IASM代码,应该可以说是IASM的衍生品,不过增加了不少有用的扩展。它是MySQL的默认数据表类型,基于了传统的ISAM类型,ISAM是Indexed Sequential Access Method(有索引的顺序访问方法)的缩写,一般来说,它是存储记录和文件的标准方法。与其他存储引擎比较,MyISAM具有检查和修复表格的大多数工具。ISAM表格可以被压缩,而且它们支持全文搜索,不过它们是事务不安全的,而且也不支持外键。如果事务回滚将会造成不完全回滚,从而不具备原子性。所以假如忽略事务以及访问并发性的话,并且需要执行大量的SELECT检索语句的话,MyISAM将是最好的选择。
InnoDB
InnoDB是MySQL 4.0之后推出的一种比较新的数据表类型,这种类型是事务安全的。它与BDB类型具有相同的特性,它们还支持外键。InnoDB表格速度很快具有比BDB还丰富的特性,因此如果需要一个事务安全的存储引擎,建议使用它。如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,同样应该使用InnoDB表。对于支持事务的InnoDB类型的表来说,影响速度的主要原因是AUTOCOMMIT默认设置是打开的,而且程序没有显式调用BEGIN 开始事务,导致每插入一条都自动提交,严重影响了速度。可以在执行sql前调用begin,多条sql形成一个事物(即使autocommit打开也可以),将大大提高性能。
Gemeni
Gemeni表,据听说也是在MySQL 4.0之后推出的,不过截至当前,很少有针对它的介绍,同样应用也就更少了,我们暂时不作介绍。
MySQL的数据表类型很多,其中比较重要的是MyISAM,InnoDB这两种。
这两种类型各有优缺点,需要根据实际情况选择适合的,MySQL支持对不同的表设置不同的类型。下面做个简单的对比:
MyISAM表类型是一种比较成熟稳定的表类型,但是MyISAM对一些功能不支持。
2.启动和关闭mysql服务器
启动:net start mysql;
关闭:net stop mysql;
在启动mysql服务后,打开windows任务管理器,会有一个名为mysqld.exe的进程运行,所以mysqld.exe才是MySQL服务器程序。
(备注:这里是操作mysql的服务,不是登录操作)
一个数据库服务器可以管理多个数据库,可以认为是一个数据的“仓库”,一般一个web应用对应一个数据库。
3.登录客户端
登录:mysql -u root -p 123 -h localhost;
-u:后面的root是用户名,这里使用的是超级管理员root;
-p:后面的123是密码,这是在安装MySQL时就已经指定的密码;
-h:后面给出的localhost是服务器主机名,它是可以省略的,例如:mysql -u root -p 123;
退出:quit或exit;
4.语言
SQL--Structured Query Language, 结构化查询语言,是关系型数据库通用的操作语言。
是一种非过程性语言。
由美国国家标准局(ANSI)与国际标准化组织(ISO)制定SQL标准。各大数据库厂商都对其做了实现。所以我们只要学会了SQL语言,就可以操作各大关系型数据库了。
为加强SQL的语言能力,各厂商增强了过程性语言的特征,增加了一些非标准的SQL,这样的SQL称为该数据库的“方言”。
SQL是用来存取关系数据库的语言,具有查询、操纵、定义和控制关系型数据库的四方面功能
5.创建数据库
~创建一个名称为mydb1的数据库。
CREATE DATABASE mydb1;
~创建一个使用gbk字符集的mydb2数据库。
CREATE DATABASE mydb2 CHARACTER SET gbk;
(CHARACTER SET:设置字符集)
(备注,utf-8编码在这里应该写utf8)
~创建一个使用utf8字符集,并带校对规则的mydb3数据库。
CREATE DATABASE mydb3 CHARACTER SET utf8 COLLATE utf8_bin;
(COLLATE:设置校对规则)
6.查看数据库
~查看当前数据库服务器中的所有数据库
SHOW DATABASES;
~查看前面创建的mydb2数据库的定义信息
SHOW CREATE DATABASE mydb2;
7.修改数据库
~查看服务器中的数据库,并把mydb2库的字符集修改为utf8
ALTER DATABASE mydb2 CHARACTER SET utf8;
(alter:修改)
8.删除数据库
~删除前面创建的mydb1数据库
DROP DATABASE mydb1;
(drop:删除)
8.1 备份和恢复数据库
(1)备份数据库
cmd窗口中使用mysqldump 备份数据库
指令:mysqldump -u root -p db_name > c:/xxx.sql
例如:mysqldump -u root -p mydb2 > c:/mydb2.sql
(2)恢复数据库:
方式1:cmd窗口中使用mysql命令 恢复数据库,注意,只能恢复数据库中的数据,不能恢复数据库本身!所以要提前建好数据库.
指令:mysql -u root -p db_name < c:/xxx.sql
例如:mysql -u root -p mydb2 < c:/mydb2.sql
方式2:在mysql命令下,source xxx.sql,这个命令的作用就是,在当前位置执行sql文件中的所有的sql.首先新建出数据库,进入数据库,在source执行备份的sql文件即可。
例如:source c:/xxx.sql
注意:如果在cmd窗口下,执行出现“拒绝访问”提示,用管理员打开cmd窗口即可。
9.选择数据库
选择数据库:
use 数据库名;
查询当前选择的数据:
select database();
没有退出数据库的命令,如果想退出当前数据库进入另一个数据,直接use 另一个数据库 就可以了
10.sql中常见的数据类型
1)字符串型
VARCHAR:
变长的字符串,需要在声明字段时指定能存储的最大字符数,真实占用的空间取决于存入的字符数,存入的越多占用空间越多。适合保存内容长度不定的字符类型数据。能包含数据的大小,mysql5.0以前0~255字节,mysql5.0以后0~65535字节
CHAR:
定长字符串,需要在声明字段时指定固定字符数。即使存入的字符数少于该长度,该字段也会占用该固定长度。适合存储长度不变的字符类型数据。能包含数据的大小,0~255字节
2)大数据类型
BLOB:
大二进制类型,可以存入二进制类型的数据,通过这个字段,可以将图片、音频、视频等数据以二进制的形式存入数据库。最大为4GB。
TEXT:
大文本,被声明为这种类型的字段,可以保存大量的字符数据,最大为4GB。
注意:text属于mysql的方言,在其他数据库中为clob类型
3)数值型
TINYINT:占用1个字节,相对于java中的byte
SMALLINT:占用2个字节,相对于java中的short
INT:占用4个字节,相对于java中的int
BIGINT:占用8个字节,相对于java中的long
FLOAT:4字节单精度浮点类型,相对于java中的float
DOUBLE:8字节双精度浮点类型,相对于java中的double
4)逻辑型
BIT:
位类型,可以存储指定位的值,可以指定位的个数,如果不指定则默认值为1位,即只能保存0或1,对应到java中可以是boolean型。
5)日期型
DATE:日期
TIME:时间
DATETIME:日期时间
TIMESTAMP:时间戳
**DATETIME和TIMESTAMP的区别?
* DATETIME和TIMESTAMP显示的结果是一样的,都是固定的"YYYY-MM-DD HH:MM:SS"的格式
* DATETIME支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。TIMESTAMP的显示范围是'1970-01-01 00:00:00'到2037年,且其实际的存储值为1970年到当前时间的毫秒数。
* 在建表时,列为TIMESTAMP的日期类型可以设置一个默认值,而DATETIME不行。
* 在更新表时,可以设置TIMESTAMP类型的列自动更新时间为当前时间。
11.设置主键约束
主键约束要求字段必须不能为空且值必须唯一,主键约束为默认索引。
增加主键约束:PRIMARY KEY
指定主键自增:auto_increment,
增加唯一约束:unique,
增加非空约束:not null
写法:
mysql> create table sss(
-> id int(11) primary key auto_increment not null unique);
12.设置外键约束
例如:新建表操作,主表a,子表b,
先建附表
CREATE TABLE `b` (
`pid` int(100) PRIMARY KEY NOT NULL,
`username` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,);
再建主表,在主表上增加外键,
CREATE TABLE `a` (
`id` int(11) PRIMARY KEY NOT NULL,
`name` varchar(20) DEFAULT NULL,
`zhanghao` int(100) DEFAULT NULL,
CONSTRAINT `a_ibfk_1` FOREIGN KEY (`zhanghao`) REFERENCES `b` (`pid`) ON DELETE SET NULL ON UPDATE CASCADE);
翻译解释:
外键名称`a_ibfk_1` 做主键的列 (`主表列`) 关联到 `子表名` (`子表列`) 当删除操作时 SET NULL 当更新时CASCADE
含义:
CASCADE 删除包含与已删除键值有参照关系的所有记录
SET NULL 修改包含与已删除键值有参照关系的所有记录,使用NULL值替换(只能用于已标记为NOT NULL的字段)
RESTRICT 拒绝删除要求,直到使用删除键值的辅助表被手工删除,并且没有参照时(这是默认设置,也是最安全的设置)
NO ACTION 啥也不做
13.添加外键
alter table locstock add foreign key locstock_ibfk2(stockid) references product(stockid)
翻译:
alter table 主表名add foreign key 外键名(主表列) references 子表名(子表列)
locstock 为表名, locstock_ibfk2 为外键名 第一个括号里填写外键列名, product为表名,第二个括号里是写外键关联的列名
14.删除外键
语法: ALTER TABLE table-name DROP FOREIGN KEY key-id;
翻译: ALTER TABLE 主表名 DROP FOREIGN KEY 外键名;
15.查看表有哪些外键
show create table locstock
16.mysql创建外键失败的9种原因
1, 两个字段的类型或者大小不严格匹配,例如,如果一个是INT(10), 那么外键也必须设置成INT(10), 而不是 INT(11) 也不能是 TINYINT. 你得使用 SHOW 命令来查看字段的大小,因为一些查询浏览器有时候把 int(10) 和int(11) 都显示为integer。另外,你还必须确定两个字段是否一个为 SIGNED,而另一个又是UNSIGNED, 这两字段必须严格地一致匹配,更多关于signed 和 unsigned 的信息,请参阅:http://www.verysimple.com/blog/?p=57
2, 你试图引用的其中一个外键没有建立起索引,或者不是一个primary key , 如果其中一个不是primary key 的放,你必须为它创建一个索引。
3, 外键的名字是一个已经存在的一个键值了,这个时候,你应该检查你的数据库以确保外健名字是唯一的,或者你在键名后面加上几个随机的字符以测试是否是这个原因。
4, 其中一个或者两个表是MyISAM引擎的表,若想要使用外键约束,必须是InnoDB引擎,(实际上,如果两个表都是MyISAM 引擎的,这个错误根本不会发生,但也不会产生外键),你可以通过查询浏览器来设置表的引擎类型
5, 你可能设置了ON DELETE SET NULL, 但是相关的键的字段又设置成了NOTS NULL 值。你可能通过修改cascade 的属性值或者把字段属性设置成 allow null 来搞定这个bug.
6, 请确定你的Charset 和 Collate 选项在表级和字段级上的一致
7, 你可能设置为外键设置了一个默认值,如 default=0
8, 在这个关系里面,其中的一个字段是一个混合键值中的一个,它没有自己独立的索引,这时,你必须为它创建一个独立的索引。
9, ALTER 声明中有语法错误
17.外键的读法误区
表1的确是主表,表2是子表,但不是叫做给表1添加一个外键,而是给表2添加一个外键,表2中的学号 字段就叫外键,它是表1学号字段的主键。你可以这样说:表1的学号字段是表2的外键。
18.MYSQL外键的使用以及优缺点
主键和索引是不可少的,不仅可以优化数据检索速度,开发人员还省不其它的工作,
矛盾焦点:数据库设计是否需要外键。这里有两个问题:一个是如何保证数据库数据的完整性和一致性;二是第一条对性能的影响。
正方观点:
1,由数据库自身保证数据一致性,完整性,更可靠,因为程序很难100%保证数据的完整性,而用外键即使在数据库服务器当机或者出现其他问题的时候,也能够最大限度的保证数据的一致性和完整性。
eg:数据库和应用是一对多的关系,A应用会维护他那部分数据的完整性,系统一变大时,增加了B应用,A和B两个应用也许是不同的开发团队来做的。他们如何协调保证数据的完整性,而且一年以后如果又增加了C应用呢?
2,有主外键的数据库设计可以增加ER图的可读性,这点在数据库设计时非常重要。
3,外键在一定程度上说明的业务逻辑,会使设计周到具体全面。
反方观点:
1,可以用触发器或应用程序保证数据的完整性
2,过分强调或者说使用主键/外键会平添开发难度,导致表过多等问题
3,不用外键时数据管理简单,操作方便,性能高(导入导出等操作,在insert, update, delete 数据的时候更快)
eg:在海量的数据库中想都不要去想外键,试想,一个程序每天要insert数百万条记录,当存在外键约束的时候,每次要去扫描此记录是否合格,一般还不 止一个字段有外键,这样扫描的数量是成级数的增长!我的一个程序入库在3个小时做完,如果加上外键,需要28个小时!
结论:
1,在大型系统中(性能要求不高,安全要求高),使用外键;在大型系统中(性能要求高,安全自己控制),不用外键;小系统随便,最好用外键。
2,用外键要适当,不能过分追求
3,不用外键而用程序控制数据一致性和完整性时,应该写一层来保证,然后个个应用通过这个层来访问数据库。
需要注意的是:MySQL允许使用外键,但是为了完整性检验的目的,在除了InnoDB表类型之外的所有表类型中都忽略了这个功能。这可能有些怪异,实际上却非常正常:对于数据库的所有外键的每次插入、更新和删除后,进行完整性检查是一个耗费时间和资源的过程,它可能影响性能,特别是当处理复杂的或者是缠绕的连接树时。因而,用户可以在表的基础上,选择适合于特定需求的最好结合。所以,如果需要更好的性能,并且不需要完整性检查,可以选择使用MyISAM表类型,如果想要在MySQL中根据参照完整性来建立表并且希望在此基础上保持良好的性能,最好选择表结构为innoDB类型
19.新增表
语法:
CREATE TABLE table_name
(
field1 datatype,
field2 datatype,
field3 datatype
)[character set 字符集] [collate 校对规则]
field:指定列名 datatype:指定列类型
创建表时,一般不需要指定字符集编码和校对规则,和数据库保持一致即可。
20.查看表
查看表结构:
desc tabName
查看当前所有表:
show tables
查看当前数据库表建表语句
show create table tabName;
21.修改表
~在上面员工表的基础上增加一个image列。
alter table employee add image blob;
~修改job列,使其长度为60。
alter table employee modify job varchar(60);
~删除gender列。
alter table employee drop gender;
~表名改为user。
alter table employee rename to user;
或
rename table employee to user;
~列名name修改为username
alter table user change name username varchar(20);
~将image插入到gender列的后面
alter table user modify image blob after gender;
~修改表的字符集为utf8
alter table user character set utf8;
22.删除表
~删除user表
drop table user;
23.增加表数据 insert into 表名(列名) values(数据)
INSERT INTO tabname [(column [, column...])] VALUES (value [, value...]);
翻译:
INSERT INTO 表名(列名,列名,列名)VALUES (数据,数据,数据);
注意:
插入的数据应与字段的数据类型相同
数据的大小应在列的规定范围内
在values中列出的数据位置必须与被加入的列的排列位置相对应
字符串和日期格式的数据要用单引号引起来
如果要插入所有字段可以省写列列表,直接按表中字段顺序写值列表
24.mysql乱码解决
查看当前数据库中字符集配置:
语法:show variables like'character%';
其中:
client是客户端使用的字符集。
connection是连接数据库的字符集设置类型,如果程序没有指明连接数据库使用的字符集类型就按照服务器端默认的字符集设置。
database是数据库服务器中某个库使用的字符集设定,如果建库时没有指明,将使用服务器安装时指定的字符集设置。
results是数据库给客户端返回时使用的字符集设定,如果没有指明,使用服务器默认的字符集。
server是服务器安装时指定的默认字符集设定。
system是数据库系统使用的字符集设定。(utf-8不可修改)
set names xxx; 命令是客户端通知服务器和当前客户端交互时使用什么编码,但是这种方式每次新开客户端都需要通知服务器 很麻烦
我们可以修改mysql/my.ini,将default-character-set=gbk,这是修改服务器默认认为的客户端的字符集编码
这样一来,大部分人都是gbk的客户端,不需要设置任何东西,连进来就没乱码.如果有个别的人客户端不是gbk,也可以通过set names xxx;的方式声明自己的编码集,也没有乱码.
25.更新表数据 update (表名) set 列名=数据 where 条件语句
语法:
UPDATE tab_name SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition]
翻译:UPDATE 表名 SET 列名=数据 WHERE 条件语句。
UPDATE语法可以用新值更新原有表行中的各列。
SET子句指示要修改哪些列和要给予哪些值。
WHERE子句指定应更新哪些行。如没有WHERE子句,则更新所有的行。
例如:
~将所有员工薪水修改为5000元。
update employee set salary=5000;
~将姓名为’张飞’的员工薪水修改为3000元。
update employee set salary=3000 where name='张飞';
~将姓名为’关羽’的员工薪水修改为4000元,job改为”耍大刀”。
update employee set salary=4000,job='耍大刀' where name='关羽';
~将刘备的薪水在原有基础上增加1000元。
update employee set salary=salary+1000 where name='刘备';
26.删除表数据 delete from
语法:
delete from tab_name [WHERE where_definition]
where用来筛选要删除的记录,如果不使用where子句,将删除表中所有数据。
delete语句不能删除某一列的值(可使用update)
delete语句仅删除记录,不删除表本身。如要删除表,使用drop table语句。
TRUNCATE TABLE tab_name语句也可以删除表中数据,它和delete有所不同。delete是一条条删除记录,truncate是摧毁整表再重建相同结构的表,truncate效率更高。
练习:
~删除表中名称为’张飞’的记录。
delete from employee where name='张飞';
~删除表中所有记录。
delete from employee;
~使用truncate删除表中记录。
truncate table employee;
27,查询表数据 select(列名) from (表名)
(1)基本的查询
语法:
SELECT [DISTINCT] *|{column1, column2. column3..} FROM table;
select 指定查询哪些列的数据。
column指定列名。
*号代表查询所有列。
from指定查询哪张表。
DISTINCT可选,指显示结果时,是否剔除重复数据
--------------------------------------------------
(2)使用where子句的查询
语法:
Select *|列名 from tablename [WHERE where_definition]
其中Where子句中支持:
Like语句中,% 代表零个或多个任意字符,_ 代表一个字符,例first_name like ‘_a%’;
练习:
~查询姓名为关羽的学生成绩
select * from exam where name='关羽';
~查询英语成绩大于90分的同学
select * from exam where english > 90;
~查询总分大于230分的所有同学
select name 姓名,english+math+chinese 总分 from exam where english+math+chinese>230;
~查询语文分数在 80-100之间的同学。
select name,chinese from exam where chinese between 80 and 100;
~查询数学分数为75,76,77的同学。再查询分数不在这个范围内的同学
select name,math from exam where math in (75,76,77);
select name,math from exam where math not in (75,76,77);
~查询所有姓张的学生成绩。
select * from exam where name like '张%';
select * from exam where name like '张_';
select * from exam where name like '张__';
~查询数学分>70,语文分>80的同学。
select * from exam where math>70 and chinese>80;
-------------------------------------------------
(3)排序查询 order by
语法:
SELECT column1, column2. column3.. FROM table order by column asc|desc;
翻译:SELECT 列名 FROM 表名 order by 列名 asc或者desc;
Order by 指定排序的列,排序的列即可是表中的列名,也可以是select 语句后指定的列名。
Asc 升序、Desc 降序
ORDER BY 子句应位于SELECT语句的结尾。
练习:
~对英语成绩排序后输出。
select name ,english from exam order by english desc;
~对总分排序按从高到低的顺序输出
select name 姓名, ifnull(english,0)+ifnull(math,0)+ifnull(chinese,0) 总分 from exam order by 总分 desc;
~对姓张的学生成绩排序输出
select name 姓名, ifnull(english,0)+ifnull(math,0)+ifnull(chinese,0) 总分 from exam where name like '张%' order by 总分 desc;
-------------------------------------------------
(4)聚合函数
SQL提供的聚合函数有计数函数COUNT()、求和函数SUM()、平均值函数AVG()、最大值函数MAX()、最小值函数MIN()等。如下表:
函数名称 |
函数功能 |
COUNT() |
返回选取结果集中行的数目 |
SUM() |
返回选取结果集中所有值的总和 |
AVG() |
返回选取结果集中所有值的平均值 |
MAX() |
返回选取结果集中所有值的最大值 |
MIN() |
返回选取结果集中所有值的最小值 |
--------------------------------------
(5)分组查询 group by
语法:
SELECT column1, column2. column3.. FROM table group by column having ...
**where子句和having子句都可以进行过滤器,但是使用场景有所不同:
* where子句对分组之前的数据进行过滤,不能使用聚合函数
* having子句对分组之后的数据进行过滤,可以使用聚合函数
* 使用where子句的地方都可以用having替代,但是使用having的地方一般不能用 where替代
28,多表查询,笛卡尔积查询
指令 select * from table1,table2;
29.内连接查询 inner join(表名)on (对等条件,就是外键关系)
select * from dept ,emp where dept.id = emp.dept_id;
或者
select * from dept inner join emp on dept.id = emp.dept_id;
结果中只有两边都有对应数据的数据才能被查出来。
30. 左外连接查询: left join表名 on(对等条件,就是外键关系)
在内连接的基础上增加上左边表有而有边表没有的记录
语法:select * from dept left join emp on dept.id = emp.dept_id;
#其中,left join 也可以写成 left outer join;
31.右外连接查询:right join 表名(对等条件,就是外键关系)
语法:select * from dept right join emp on dept.id = emp.dept_id;
#其中,right join 也可以写成 right outer join;
32.全外连接查询:full join
在内连接的基础上增加左边表有而右边表没有的记录和右边表有而左边表没有的记录
#mysql 不支持全外连接,但是其他的数据库支持,比如SQL Server
select * from dept full join emp on dept.id = emp.dept_id;
#我们可以在mysql中使用union关键字模拟全外连接
select * from dept left join emp on dept.id = emp.dept_id
union
select * from dept right join emp on dept.id = emp.dept_id;
#其中,full join 也可以写成 full outer join;
33.Where 和Having 区别
1.用的地方不一样
where可以用于select、update、delete和insert...into语句中。
having只能用于select语句中
2.执行的顺序不一样
where的搜索条件是在执行语句进行分组之前应用 having的搜索条件是在分组条件后执行的
即如果where和having一起用时,where会先执行,having后执行
3.子句有区别
where子句中的条件表达式having都可以跟,而having子句中的有些表达式where不可以跟;having子句可以用集合函数(sum、count、avg、max和min),而where子句不可以。 有些地方两者都可以用,比如
having:select studentid, avg(score) from studentScore
group by studentid
having left(studentid, 1)='0'
where:select studentid, avg(score) from studentScore
where left(studentid, 1)='0'
group by studentid
这种情况下哪个会快一点
解析:
select studentid, avg(score) from studentScore group by studentid having left(studentid, 1)='0'
1、分组汇总
2、过滤非法项
left(studentid, 1)='0'是个效率不很高的过滤条件,如果分组会使数据量极大减少(比如每个人有几十门课),而且要过滤掉的只是很小一部分学生,这种写法会有比较高的效率
select studentid, avg(score) from studentScore where left(studentid, 1)='0' group by studentid
1、过滤非法项
2、分组汇总
虽然left(studentid, 1)='0'是个效率不很高的过滤条件,但是如果你要从几百万学生中找到几十个学生3-5门功课的平均分,还是应该很明智的选择它