MySQL高级查询


layout: post
title: "MySQL高级查询"
date: 2016-06-02 11:14:38 +0800
comments: true
categories: [mysql]


前段时间了解了点数据库优化的内容,但是发现自己对很多数据库的高级查询还不是很数据。

下面就整理下最近看的一些高级查询:

emp_id emp_name emp_age emp_sal emp_bir emp_sex
100001 红枫 29 9000 1977-01-01 male
100002 丽鹃 27 8000 1979-12-31 fmale
100005 啸天 27 4000 1979-07-10 male

查询结果的字段联合和重新命名

  • select concat(emp_id," ",emp_name) from emp;

查询结果:

concat(emp_id," ",emp_name)
100005 啸天
100001 红枫
100002 丽鹃

用AS关键字重新给输出结果命名标题

  • select concat(emp_id," ",emp_name) as info from emp;

查询结果:

info
100005 啸天
100001 红枫
100002 丽鹃

GROUP BY

group by语法可以根据给定数据列的每个成员对查询结果进行分组统计,最终得到一个分组汇总表。

SELECT子句中的列名必须为分组列或列函数。列函数对于GROUP BY子句定义的每个组各返回一个结果。

  • select emp_sex,count(*) from emp group by emp_sex;

查询结果如下:

emp_sex count(*)
fmale 1
male 2
  1. 满足“SELECT子句中的列名必须为分组列或列函数”,因为SELECT有GROUP BY emp_sex中包含的列emp_sex。
  2. “列函数对于GROUP BY子句定义的每个组各返回一个结果”,根据性别分组,对每个性别返回一个结果,就是每个性别人人数。

从多个数据表中检索信息

-> where emp.emp_id=dept.dept_id;```

UNIN 用法

union:联合的意思,即把两次或多次查询结果合并起来。

  • 要求:两次查询的列数必须一致
  • 推荐:列的类型可以不一样,但推荐查询的每一列,相对应的类型一样
  • 可以来自多张表的数据:多次sql语句取出的列名可以不一致,此时以第一个sql语句的列名为准。

如果不同的语句中取出的行,有完全相同(这里表示的是每个列的值都相同),那么union会将相同的行合并,最终只保留一行。也可以这样理解,union会去掉重复的行。

如果不想去掉重复的行,可以使用union all``。 如果子句中有order by,limit```,需用括号()包起来。推荐放到所有子句之后,即对最终合并的结果来排序或筛选。

如:(select * from a order by id) union (select * from b order id);

在子句中,order by 需要配合limit使用才有意义。如果不配合limit使用,会被语法分析器优化分析时去除。

注意一点表项的结构必须相同,比如两个表的id int(10) 如果其中一个换成id int(9) 也不行,查询将会报错。但可以有不同的名称(不推荐),查询结果列将以SQL收到的第一份列名为准输出

<pre class="prettyprint linenums">
hotnews=mysql_query("SELECT id,title,pageview,tablenm FROM News UNION SELECT id,title,pageview,tablenm FROM Informs UNION SELECT id,title,pageview,tablenm FROM Article UNION SELECT id,title,pageview,tablenm FROM IntroORDER BY pageview DESC limit 15",conn);//获取在四个表中按浏览数高低排序的前15个文章
</pre>


Join

join 用于多表中字段之间的联系,语法如下:

from table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona

table1:左表;table2:右表。

join按照功能大致分为如下三类:

inner join(内连接,或等值连接):取得两个表中存在连接匹配关系的记录。

LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录。

RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并无匹配对应记录。

注意:mysql不支持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join.

接下来给出一个列子用于解释下面几种分类。如下两个表(A,B)

mysql> select A.id,A.name,B.name from A,B where A.id=B.id;

id name name
1 Pirate Rutabaga
2 Monkey Pirate
3 Ninja Darth Vader
4 Spaghetti Ninja

4 rows in set (0.00 sec)

Inner join

内连接,也叫等值连接,inner join产生同时符合A和B的一组数据。

mysql> select * from A inner join B on A.name = B.name;

id name id name
1 Pirate 2 Pirate
3 Ninja 4 Ninja

Left join

mysql> select * from A left join B on A.name = B.name;

或者:select * from A left outer join B on A.name = B.name;

id name id name
1 Pirate 2 Pirate
2 Monkey NULL NULL
3 Ninja 4 Ninja
4 Spaghetti NULL NULL

4 rows in set (0.00 sec)

left join,(或left outer join:在Mysql中两者等价,推荐使用left join.)左连接从左表(A)产生一套完整的记录,与匹配的记录(右表(B)) .如果没有匹配,右侧将包含null。

如果想只从左表(A)中产生一套记录,但不包含右表(B)的记录,可以通过设置where语句来执行,如下:

mysql> select * from A left join B on A.name=B.name where A.id is null or B.id is null;

id name id name
2 Monkey NULL NULL
4 Spaghetti NULL NULL

2 rows in set (0.00 sec)

同理,还可以模拟inner join. 如下:

mysql> select * from A left join B on A.name=B.name where A.id is not null and B.id is not null;

id name id name
1 Pirate 2 Pirate
3 Ninja 4 Ninja

2 rows in set (0.00 sec)

求差集:

根据上面的例子可以求差集,如下:

SELECT * FROM A LEFT JOIN B ON A.name = B.name
WHERE B.id IS NULL
union

SELECT * FROM A right JOIN B ON A.name = B.name
WHERE A.id IS NULL;

结果

id name id name
2 Monkey NULL NULL
4 Spaghetti NULL NULL
NULL NULL 1 Rutabaga
NULL NULL 3 Darth Vader

Right join

mysql> select * from A right join B on A.name = B.name;

id name id name
NULL NULL 1 Rutabaga
1 Pirate 2 Pirate
NULL NULL 3 Darth Vader
3 Ninja 4 Ninja

4 rows in set (0.00 sec)

USING(column_list)子句
用于为一系列的列进行命名,这些列必须同时在两个表中存在
SELECT java.,mysql. FROM java LEFT JOIN mysql USING (name);

关于join的一个小测试:

有这样两个表:

message:

|id | username |message |
| ---------|:-------------:|
|1 |ewan |123|
|2 |wean2| 123|
|3 |1 |??|
|4 |1 |2343|
|5 |1 |sdfjkl|

user:

|id | username |password |
| ---------|:-------------:|
|1 |1|22|
|2 |2| 111|
|3 |Ewan2 |22|
|4 |Ewan5 |22|

测试如下:

<?php
$dsn="mysql:host=127.0.0.1;dbname=test";
$username="root";
$password="";
try{
    $pdo= new PDO($dsn,$username,$password);
}catch(PDOException $e){
    echo $e->getMessage();
}
$sql="SELECT * FROM message LEFT JOIN user ON message.id=user.id";
$back=$pdo->query($sql);
$back=$back->fetchAll(PDO::FETCH_ASSOC);
print_r($back);

输出结果:

Array
(
[0] => Array
    (
        [id] => 1
        [username] => 1
        [message] => 123
        [password] => 22
    )

[1] => Array
    (
        [id] => 2
        [username] => 2
        [message] => 123
        [password] => 111
    )

[2] => Array
    (
        [id] => 3
        [username] => Ewan2
        [message] => ??
        [password] => 22
    )

[3] => Array
    (
        [id] => 
        [username] => 
        [message] => 2343
        [password] => 
    )

[4] => Array
    (
        [id] => 
        [username] => 
        [message] => sdfjkl
        [password] => 
    )

)

可以看到在两个表都有username的情况下只取了前面的那个username而舍弃了后一个。


HAVING

HAVING 子句对 GROUP BY 子句设置条件的方式与 WHERE 和 SELECT 的交互方式类似。WHERE 搜索条件在进行分组操作之前应用;而 HAVING 搜索条件在进行分组操作之后应用。HAVING 语法与 WHERE 语法类似,但 HAVING 可以包含聚合函数。HAVING 子句可以引用选择列表中显示的任意项。

显示每个地区的总人口数和总面积.仅显示那些面积超过1000000的地区。

SELECT region, SUM(population), SUM(area) 
FROM bbc 
GROUP BY region 
HAVING SUM(area)>1000000 

在这里,我们不能用where来筛选超过1000000的地区,因为表中不存在这样一条记录。

我们在写sql语句的时候,经常会使用where语句,很少会用到having,其实在mysql中having子句也是设定条件的语句与where有相似之处但也有区别。having子句在查询过程中慢于聚合语句(sum,min,max,avg,count).而where子句在查询过程中则快于聚合语句(sum,min,max,avg,count)。

简单说来:

where子句:  
select sum(num) as rmb from order where id>10  
//先查询出id大于10的记录才能进行聚合语句  
 
having子句:  
select reportsto as manager, count(*) as reports from employees  
group by reportsto having count(*) > 4

having条件表达示为聚合语句。肯定的说having子句查询过程慢于聚合语句。
再换句说话说把上面的having换成where则会出错。统计分组数据时用到聚合语句。

对分组数据再次判断时要用having。如果不用这些关系就不存在使用having。直接使用where就行了。
having就是来弥补where在分组数据判断时的不足。因为where要快于聚合语句。

这几个关键字执行的顺序

关键字是按照如下顺序进行执行的:

  • Where
  • Group By
  • Having
  • Order by

首先where将最原始记录中不满足条件的记录删除(所以应该在where语句中尽量的将不符合条件的记录筛选掉,这样可以减少分组的次数)

然后通过Group By关键字后面指定的分组条件将筛选得到的视图进行分组
接着系统根据Having关键字后面指定的筛选条件,将分组视图后不满足条件的记录筛选掉

最后按照Order By语句对视图进行排序,这样最终的结果就产生了。

注意:

凡是在group by后面出现的字段,必须同时在select后面出现;

凡是在select后面出现的、同时未在聚合函数中出现的字段,必须同时出现在group by后面.

having 子句被限制子已经在SELECT语句中定义的列和聚合表达式上。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容

  • 主流关系型数据库 关系型数据库存储数据的特点 结构化查询语言: 数据类型: select * from emp; ...
    陈先森mansplain阅读 676评论 0 0
  • 一、SQL速成 结构查询语言(SQL)是用于查询关系数据库的标准语言,它包括若干关键字和一致的语法,便于数据库元件...
    shadow雨轩阅读 509评论 0 3
  • 在面对诱惑的时候,多数人从心底想抵抗诱惑,但是我们和诱惑正面交锋的时候只愿意选择短期的及时的奖励。这是由于我们的大...
    木木me阅读 198评论 0 0
  • 那一夜,我听了一宿梵唱,不为参悟,只为寻你的一丝气息。 那一月,我转过所有经轮,不为超度,只为触摸你的指纹。 那一...
    大佳和小米阅读 187评论 0 0
  • 刚刚尝到一点甜头,就忍不住又画了一个小姐姐。在画眼睛的时候感觉比上一个小姐姐更有神了呢,主要是我调整了眼珠的位置,...
    陆薇阅读 250评论 0 2