您的位置:首页 > 数据库 > MySQL

网易MySQL数据库工程师微专业学习笔记(二)

2016-12-24 23:13 387 查看
一、连接与子查询的区别

连接与子查询都是用于连接多张表中的数据,在mysql内部实现的时候就是通过多重循环来实现的。以两张表为例,其实mysql在查询数据时就是通过一个二重循环来实现的,而在外层的循环中涉及的表就是查询的驱动表,当没有其他的查询条件时驱动表必定是要全表扫描的,而内层循环的表可以使用索引来加快查询,到这里为止连接与子查询都是一样的。两者的区别在于子查询中驱动表必定是in外部的表,而连接操作时mysql会根据数据量来自动选择数据量少的表作为驱动表,因此连接的效率往往是要优于子查询的。

二、count(*)、count(1)和count(column)的区别

count(*)和count(1)基本是一样的,在性能上没有什么差别。count(column)(column是指具体的表中的一列)和count(*)的差别在于当对column进行count时,如果column列中的值为null时这一行的记录就不会计算在统计结果中。

三、group_concat函数

这个函数时mysql中独有的,在使用时通常与group by同时使用,功能是将一个分组内的某个列中的所有的字符串连接并以逗号分隔,例如有分类表和文章表两张表,其结构如下:

CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(50) NOT NULL DEFAULT '' COMMENT '标题',
  `updatetime` varchar(50) NOT NULL DEFAULT '1000-01-01 00:00:00' COMMENT '发布时间',
  `classify` int(11) NOT NULL DEFAULT '0' COMMENT '分类Id',
  `abstract` text NOT NULL COMMENT '摘要',
  `body` text NOT NULL COMMENT '正文',
  `account` int(11) NOT NULL DEFAULT '0' COMMENT '发布用户Id',
  `titlephoto` varchar(255) NOT NULL COMMENT '封面图',
  `count` int(11) NOT NULL DEFAULT '0' COMMENT '点击数',
  `recommend` tinyint(11) NOT NULL DEFAULT '0' COMMENT '是否置顶',
  `status` tinyint(11) NOT NULL DEFAULT '1' COMMENT '是否被删除',
  PRIMARY KEY (`id`),
  KEY `FK_article_account` (`account`),
  KEY `FK_article_classify` (`classify`),
  CONSTRAINT `FK_article_account` FOREIGN KEY (`account`) REFERENCES `account` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `FK_article_classify` FOREIGN KEY (`classify`) REFERENCES `classify` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8
CREATE TABLE `classify` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL DEFAULT '' COMMENT '分类名称',
  `count` int(11) NOT NULL DEFAULT '0' COMMENT '该分类下的文章数',
  `account` int(11) NOT NULL DEFAULT '0' COMMENT '发布用户Id',
  `status` tinyint(11) NOT NULL DEFAULT '1' COMMENT '是否被删除',
  PRIMARY KEY (`id`),
  KEY `FK_classify_account` (`account`),
  CONSTRAINT `FK_classify_account` FOREIGN KEY (`account`) REFERENCES `account` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
如果我希望查询每个分类下的所有文章的标题并用逗号将标题分隔,那么就可以用到group_concat来实现,查询语句如下:

SELECT classify.`name`, group_concat(article.title) FROM classify,article where classify.id=article.classify group by classify.`name`
使用group_concat函数需要注意以下两点,第一,group_concat函数的分隔符默认是逗号,如果需要时可以修改的,再参数后面加上SEPARATOR和需要的分隔符即可,例如上例中如果我希望用分号分隔所有的标题只要这样写:

SELECT classify.`name`, group_concat(article.title SEPARATOR ';') FROM classify,article where classify.id=article.classify group by classify.`name`
第二,group_concat函数的返回值默认是能返回1024长度的数据,如果超过了是会被截断的,如果需要修改这个返回上限可以用SET GLOBAL group_concat_max_len = 1024语句进行修改,如果想查看当前group_concat函数当前能返回的最大长度可以用show global variables like '%concat%'来查询。

四、使用max和min时的注意点

当使用max和min的时候如果需要和别的列值同时显示时需要在查询中添加排序,否则查询结果是不正确的。以之前的article表为例,如果希望查询点击量最大的文章如果用这样的查询所得的结果可能是不正确的:

SELECT title, max(count) FROM `article`
因为这样查询得到的title是所有文章中Id最小的文章的title,而这一篇文章不一定是点击量最大的,如果需要完成这个查询就需要对article表按点击量降序排序,如下:

SELECT title, max(count) FROM `article` order by count desc limit 1;

五、limit,offset

limit,offset语法是用来实现查询从第几行开始连续几列数据的语法,例如查询第五个开始的十条article中的数据,可以这样写:

SELECT * FROM `article` limit 10 offset 4
这里需要注意如果是要从第n个数据开始查询,那么offset后面的数值应该是n-1。另外也可以不写offset,就使用limit,如上面的例子可以写作:

SELECT * FROM `article` limit 4,10


六、group by
group by是在实现统计业务时经常使用的方法,实现对某一列中数据的分值统计。例如统计每个用户发表的文章数量,可以用如下语句:

SELECT account, count(*) FROM `article` group by account


这里需要注意两点,第一,分组所用的字段一定要在select后面的查询字段中显示,这样才能知道分了哪些类,每个分类的值是多少;第二,分组查询中除了分组字段外其他字段应该都是某个字段在一个聚合函数中的计算结果,否则查询结果是没有意义的也可能时不稳定的(即每次查询获得的结果可能是不同的)。另外,group by也可以对多个列进行分组,这样分组时是根据多个列的值的组合进行分类统计。

七、覆盖插入、忽略插入和查询插入

普通的插入操作时,当插入的主键或者唯一索引中的值已经存在时会插入失败并报错。如果不希望mysql报错可以选择使用覆盖插入或者忽略插入,语法如下:

replace into table values(....)//覆盖查询
insert ignore into table values(....)///忽略查询
覆盖查询就是将当前插入的值去覆盖重复的行,而忽略查询则是当插入的主键或者唯一索引中的值已经存在时忽略这次插入,而不报错。

另外如果希望实现主键或者唯一索引中的值重复时只覆盖某几个字段可以使用on duplicate key update,例如当向classify中插入一个记录出现id重复时希望将name值覆盖,可以这么写:

insert into classify values(1,"test",1,1,1) on duplicate key update `name`="test"


查询插入就是将一个查询结果全部插入一张表中,主要用于复制表。语法如下:

insert into table_a select * from table_b
当然插入的表要与查询结果的字段类型一一对应。

八、select last_insert_id()

当完成一个插入后,希望查询刚才插入的数据插入后的自增Id的值可以使用select last_insert_id()。这个语句是connection级别的,因此不会因为高并发而导致数据错误。

九、case when

mysql的select的字段可以进行条件判断,例如查询article的title时希望如果长度小于10个字则全部显示,如果超过则超过部分用'...'来代替。实现语法如下:

select case when char_length(title)<=10 then title else concat(substring(title, 1, 10),'...') end from article
case when后面写的是判断条件,这里是title的长度不超过10。then后面是当条件为真时显示的查询结果,这里就是将title全部显示。else后面是当条件为假时显示的查询结果,这里用了两个函数实现将超过10的部分截断并补上'...'。最后要用end结尾。

十、delimiter // 

delimiter // 语句是用来修改mysql默认的结尾符号的。mysql中默认是用';'做为结尾符号的,但是当定义触发器、函数和存储过程时如果不修改则mysql无法区分';'指的是整个mysql语句结束还是只是内部定义的语句的结束,因此在定义触发器、函数和存储过程前需要修改mysql的默认结尾符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据库 mysql