mysql 进阶查询(学习笔记)

学习笔记,来源:实验楼 ,链接: https://www.shiyanlou.com/courses/9

 

 

 
一、日期计算:
1、要想确定每个宠物有多大,可以使用函数TIMESTAMPDIFF()计算当前日期的年和出生日期之间的差也可以按照直接使用语句(YEAR(CURDATE())-YEAR(birth))计算,其中函数CURDATE()是计算当前的日期。如果当前日期的日历年比出生日期早,则减去一年。以下代码是查询每个宠物的出生日期、当前日期和年龄(以年作为计算单位),其中关键字age是年龄这个计算结果的标签。
SELECT name, birth, CURDATE(),TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS age FROM pet;
SELECT name, birth, CURDATE(), (YEAR(CURDATE())-YEAR(birth)) - (RIGHT(CURDATE(),5)<RIGHT(birth,5)) AS age FROM pet ORDER BY name; 
YEAR()提取日期的年部分,RIGHT()提取日期最右面5个字符的MM-DD (月份和日期)部分。
 
2、查询来确定已经死亡动物的死亡年龄。你通过检查death值是否为NULL来确定是哪些动物已经死亡,然后对于那些非NULL值的动物,需要计算出death和birth值之间的差来知道他们在这个世界上所存在的时间:
SELECT name, birth, death, (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5)) AS age FROM pet WHERE death IS NOT NULL ORDER BY age; 
查询使用death IS NOT NULL而非death != NULL,因为NULL是特殊的值,不能使用普通比较符来比较。
 
3、哪个动物下个月过生日怎么办?对于这类计算,年和天是无关的,你只需要提取birth列的月份部分。MySQL提供几个日期方面的提取函数,例如YEAR()、MONTH()DAYOFMONTH()。在这里MONTH()是我们需要的函数。为了观察它的实现原理,可以运行以下简单的查询显示birth和MONTH(birth)的值:
SELECT name, birth FROM pet WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));、
DATE_ADD()允许在一个给定的日期上加上时间间隔。如果在NOW()值上加上一个月,然后用MONTH()提取月份,产生生日所在月份
 
4、完成该任务的另一个方法是加1得出当前月份的下一个月(在使用取模函数MOD()后,如果月份当前值是12,则“返回”到值0):
SELECT name, birth FROM pet WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
注意,MONTH返回在1和12之间的一个数字,且MOD(something,12)返回在0和11之间的一个数字,因此必须在MOD()后加1,否则我们将从11月(11)跳到1月(1)。
 
二、模式匹配:
1、MySQL提供标准的SQL模式匹配,以及一种基于类Unix里的程序如vi、grep和sed里的扩展正则表达式模式匹配的格式。 SQL模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零字符)。在 MySQL中,SQL的模式默认是忽略大小写的。下面给出一些例子。注意使用SQL模式时,不能使用=或!=;而应使用LIKE或NOT LIKE比较操作符。
 
要想找出以“b”开头的名字的动物信息:
mysql> SELECT * FROM pet WHERE name LIKE 'b%';
要想找出以“fy”结尾的名字:
mysql> SELECT * FROM pet WHERE name LIKE '%fy'; 
要想找出包含“w”的名字:
mysql> SELECT * FROM pet WHERE name LIKE '%w%';  
要想找出正好包含5个字符的名字,使用“_”模式字符:
mysql> SELECT * FROM pet WHERE name LIKE '_____';

  

2、由MySQL提供的模式匹配的其它类型是使用扩展正则表达式。当你对这类模式进行匹配测试时,使用REGEXPNOT REGEXP操作符(或RLIKENOT RLIKE,它们是同义词)。 
 
扩展正则表达式的一些字符是:
  • ‘.’匹配任何单个的字符。
  • 字符类“[...]”匹配在方括号内的任何字符。例如,“[abc]”匹配“a”、“b”或“c”。为了命名字符的范围,使用一个“-”。“[a-z]”匹配任何字母,而“[0-9]”匹配任何数字。
  • “ ”匹配零个或多个在它前面的字符。例如,“x”匹配任何数量的“x”字符,“[0-9]”匹配任何数量的数字,而“.”匹配任何数量的任何字符。
 
如果REGEXP模式与被测试值的任何地方匹配,模式就匹配(这不同于LIKE模式匹配,只有与整个值匹配,模式才匹配)。 为了定位一个模式以便它必须匹配被测试值的开始或结尾,在模式开始处使用“^”或在模式的结尾用“$”。 为了说明扩展正则表达式如何工作,下面使用REGEXP重写上面所示的LIKE查询:
 
为了找出以“b”开头的名字,使用“^”匹配名字的开始:
mysql> SELECT * FROM pet WHERE name REGEXP '^b'; 
如果你想强制使REGEXP比较区分大小写,使用BINARY关键字使其中一个字符串变为二进制字符串。该查询只匹配名称首字母的小写‘b’。
mysql> SELECT * FROM pet WHERE name REGEXP BINARY '^b'; 
为了找出以“fy”结尾的名字,使用“$”匹配名字的结尾:
mysql> SELECT * FROM pet WHERE name REGEXP 'fy$';  
为了找出包含一个“w”的名字,使用以下查询:
mysql> SELECT * FROM pet WHERE name REGEXP 'w';

 

3、既然如果一个正则表达式出现在值的任何地方,他就会被模式匹配,就不必在先前的查询中在模式的两侧放置一个通配符以使得它匹配整个值,就像你使用了一个SQL模式那样。
 
为了找出包含正好5个字符的名字,使用“^”和“$”匹配名字的开始和结尾,和5个“.”实例在两者之间:
mysql> SELECT * FROM pet WHERE name REGEXP '^.....$'; 
你也可以使用“{n}”重复n次操作符,重写前面的查询:
mysql> SELECT * FROM pet WHERE name REGEXP '^.{5}$';

  

三、计算行数:

计算你拥有动物的总数目与“在pet表中有多少行?”是同样的问题,因为每个宠物都对应一条记录。COUNT(*)函数计算行数,所以计算动物数目的查询应为:
mysql> SELECT COUNT(*) FROM pet;
如果你想要知道每个主人有多少宠物,你也可以使用COUNT(*)函数:
mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
注意,使用GROUP BY对每个owner的所有记录分组,没有它,你会得到错误消息:
mysql> SELECT owner, COUNT(*) FROM pet;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...)
with no GROUP columns is illegal if there is no GROUP BY clause
COUNT(*)和GROUP BY以各种形式分类你的数据。下列例子显示出以不同方式进行动物普查操作。
 
查看每种动物的数量:
mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
查看每种性别的动物数量:
mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
按种类和性别组合分类的动物数量:
mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
若使用COUNT(*),你不必检索整个表。例如, 当只对狗和猫进行查询时,应为:
mysql> SELECT species, sex, COUNT(*) FROM pet WHERE species = 'dog' OR species = 'cat' GROUP BY species, sex;

或,如果你仅需要知道已知性别的按性别分组的动物数目: 

mysql> SELECT species, sex, COUNT(*) FROM pet WHERE sex IS NOT NULL GROUP BY species, sex;

  

四、使用1个以上的表
 
pet表追踪你拥有的宠物。如果你想要记录其它相关信息,例如在他们看兽医的情况或后代出生的情况,那么你需要另外的表。这张表应该拥有些什么呢?它需要:
 
需要包含宠物名字以便你知道每个发生的事件属于哪个动物。
需要一个日期以便你知道事件是什么时候发生的。
需要一个描述事件的字段。
如果你想要对事件进行分类,则需要一个事件类型字段。
综上所述,event表的CREATE TABLE语句应为:
 
mysql> CREATE TABLE event (name VARCHAR(20), date DATE, type VARCHAR(15), remark VARCHAR(255));
 
类似于于pet表,最简单的方法是创建一个用定位符分隔的文本文件来加载载初始记录:
 
 
采用如下方式加载记录:
mysql> LOAD DATA LOCAL INFILE '/home/shiyanlou/Desktop/event.txt' INTO TABLE event; 
 
 
由于你已经在pet表上的查询中学到了一定的知识,你应该能执行对event表中记录的检索;原理是一样的。但是有没有event表本身不能回答你可能问的问题呢?
 
当宠物们生了了一窝小动物时,假定你想要找出这时候每只宠物的年龄。我们前面看到了如何通过两个日期计算年龄。event表中有母亲的生产日期,但是为了计算母亲的年龄,你需要她的出生日期,存储在pet表中。说明查询需要两个表:
mysql> SELECT pet.name,
-> (YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age,
-> remark
-> FROM pet, event
-> WHERE pet.name = event.name AND event.type = 'litter';
 
 
关于该查询要注意以下几件事:
 
FROM子句连接两个表,因为查询需要从两个表中提取信息。
当从多个表组合(联结)信息时,你需要指定其中一个表中的列明以期匹配其它表的列名。这很简单,因为它们都有一个name列,查询可以通过使用WHERE子句基于name值来匹配两个表中的记录。
 
因为name列都存在两个表中,因此当引用该列时,一定要指定是哪个表,把表名附在列名前即可以实现。 如果你想要将一个表的记录与该表的其它记录进行比较,可以将该表联结到自身。例如,为了在你的宠物之中选择繁殖中的配偶,你可以用pet表联结自身来进行相同种类的雄雌配对:
mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
-> FROM pet AS p1, pet AS p2
-> WHERE p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';  
在这个查询中,我们为表名指定别名p1和p2以便能引用它们的列并且使得每一个列的引用更直观。
 
 
五、获得数据库和表的信息
 
1、如果你忘记数据库或表的名字,或给定的表的结构是什么(例如,它的列叫什么),怎么办?MySQL提供一些语句解决这个问题。 你已经知道SHOW DATABASES可以列出由服务器管理的所有数据库。为了找出当前选择了哪个数据库,使用DATABASE()函数:
 mysql> SELECT DATABASE(); 
如果你还没选择任何数据库,结果是NULL
2、为了找出当前的数据库包含什么表(例如,当你不能确定一个表的名字),使用这个命令:
mysql> SHOW TABLES; 
3、如果你想要知道一个表的结构,可以使用DESCRIBE命令;它显示表中每个列的信息:
mysql> DESCRIBE pet;
Field显示列名字,Type是列的数据类型,Null表示列是否能包含NULL值,key显示列是否被索引而Default指定列的默认值。
如果表有索引,SHOW INDEX FROM tbl_name生成有关索引的信息。
 

 

posted @ 2018-02-25 15:34  小白爷  阅读(2112)  评论(0编辑  收藏  举报