十四:使用子查询

1:子查询是嵌套在其他查询中的查询。

2:需要列出订购TNT2的所有客户信息,需要下面几步:

a:从orderitems表中检索出包含物品TNT2的所有订单号;

b:根据上一步得出的订单号,从orders表中,检索出的所有客户ID;

c:根据上一步的客户ID,从customers中检索出客户信息;

它们针对的sql语句分别是:

a:select order_num from orderitems where prod_id = ‘TNT2’; 得到结果

b:select cust_id from orders where order_num in (20005, 20007); 得到结果如下:

c:select cust_name,cust_contact from customers where cust_id in (10001, 10004); 结果如下:

上面的三个sql语句,可以合为一句:

select cust_name,  cust_contact from customers where cust_id in

(select cust_id from  orders  where order_num in

(select order_num from orderitems where prod_id ='TNT2')

);

这就是子查询的例子,为了执行上面的sql语句,mysql实际上执行的就是一开始的那三条语句。子查询总是由内而外处理。

3:另外一个例子,比如要查询customers中,每个客户的订单总数,sql语句如下:

select cust_name, cust_state, (select count(*) from orders where orders.cust_id = customers.cust_id) as orders from customers order
by orders; 结果如下:

本例中的子查询,使用了完全限定名orders.cust_id和customers.cust_id。因为单单使用列名cust_id会有多义性。

4:注意,使用子查询并不是执行该查询最有效的方法。

十五:联接表

1:sql最强大的功能之一就是,能在数据检索查询的执行中联接表。联接表是利用SQL的select能执行的最重要的操作。

2:假如有这样的场景,有一个包含产品目录的表,每种类别的物品占一行,包括产品描述,价格,以及供应商的信息。

如果同一个供应商能生产多种物品,那么如何存储供应商信息?比如供应商名,地址,联系方法等。

将供应商信息和产品信息分开存储,理由如下:

a:因为同一供应商生产的每个产品的供应商信息都是相同的,对每个产品重复此信息既浪费时间,又浪费存储空间。

b:如果供应商信息改变,比如电话或地址变动,则只需改动一次即可;

c:如果有重复数据,则很难保证每次输入该数据的方式都相同。

关键是,相同数据出现多次,绝不是一个好事,这是关系数据库设计的基础。这个例子中,可建立两个表,一个存储供应商信息,一个存储产品信息。

vendors表存储供应商信息,每个供应商占一行,具有唯一标示。此标识称为主键。

products表存储产品信息,只存储供应商ID。vendors表的主键,又叫做products表的外键,它将vendors表和products表关联。

外键是某个表的一列,它包含另一个的主键值,定义了两个表的关系。

3:数据分成多个表存储有好处,但是也有代价,就是:如果数据存储在多个表中,如何用单条select语句检索出数据。这时,就要使用联接。它是一种机制,用来在一条select语句中关联表。联接在运行时关联表中正确的行。

联接不是物理实体,它在实际的数据库表中不存在,联接有mysql根据需要建立,存在于查询的执行当中。

4:select vend_name, prod_name, prod_price from vendors, products where vendors.vend_id = products.vend_id order by vend_name, prod_name;
结果如下:

5:在一条select语句中联接几个表时,相应的关系是在运行中构造的。在数据库的定义中不存在能指示mysql如何对表进行联接的东西,必须自己做这些事情。

在联接两个表时,实际上是将第一个表的每一行与第二个表的每一行配对。where子句使得只返回哪些匹配给定条件的行。如果没有where子句,则第一个表中的每行将与第二个表中的每行配对。返回的行数将是第一个表的行数乘以第二个表中的行数。

所以,应该保证所有联接都有where子句。

6:目前为止使用的联接称为等值联接,它基于两个表的相等测试,也称为内部联接。也可以使用另外一种语法:

select vend_name, prod_name, prod_price from vendors INNER JOIN products on vendors.vend_id = products.vend_id;

ANSI SQL规范首选inner join语法。

7:一条select语句中,可以联接的表的数目没有限制,比如:

select prod_name, vend_name, prod_price, quantity from orderitems, products, vendors where

products.vend_id = vendors.vend_id and orderitems.prod_id = products.prod_id and order_num =20005; 结果如下, 它列出了订单为20005的物品信息:

 

8:注意,运行时进行关联多个表,是非常耗费资源的。

9:上一章的例子中,返回订购TNT2产品的客户信息,可以用联接处理:

select cust_name, cust_contact from customers, orders, orderitems where

customers.cust_id= orders.cust_id and

orders.order_num= orderitems.order_num and

orderitems.prod_id= 'TNT2';  结果如下:

 

十六:创建高级联接

1:sql允许给表起别名,这样可以:缩短SQL语句;允许在单条select语句中多次使用相同的表。比如:

select cust_name, cust_contact  from customers as c, orders as o, orderitems as oi

where c.cust_id = o.cust_id and

oi.order_num = o.order_num and

andoi.prod_id = ‘TNT2’;

表别名不仅可用于where子句,还可以用于select列表,order by子句等。

2:自联结的例子:比如在products表中,查找生产‘DTNTR‘的生产商,生产的其他产品,可使用下面的子查询语句:

select prod_id, prod_name from products where

vend_id = (select vend_id from products where prod_id = ‘DTNTR’);

上面的例子,也可以使用自联结,比如:

select p1.prod_id, p1.prod_name  from products as p1, products as p2

where p1.vend_id = p2.vend_id and p2.prod_id = ‘DTNTR’;

这个例子必须使用表别名。可以想象成两个完全相同的表进行联接的情况。自联结的方式应该会比使用子查询更快一些。

3:外部联接

联接是将一个表中的行与另一个表中的行相关联,将满足条件的行返回。但有时会需要包含没有关联行的那些行。比如对每个客户下了多少订单进行计数,包括未下订单的客户。这就是外联结。

比如,检索客户及其订单,使用内联接是:

select customers.cust_id, orders.order_num from customers inner join orders on

customers.cust_id= orders.cust_id;  得到结果如下:

使用外联结:

select customers.cust_id, orders.order_num from customers left outer join orders on

customers.cust_id = order.cust_id;  得到结果如下:

可以明显的看出外联结和内联接的不同。使用outer join来指明外联结,外联结还必须指明right或left,指明需要包含所有行的表。left指明outer
join左边的表,right指明outer join右边的表。使用right的例子是:

select customers.cust_id, orders.order_num from customers right outer join orders on

orders.cust_id = customers.cust_id;

4:如果要检索所有客户以及每个客户所下的订单数,可以如下:

select customers.cust_name, customers.cust_id, count(orders.order_num) as num_ord

from customers inner join orders on customers.cust_id = orders.cust_id

group by customers.cust_id;  结果如下:

使用外联结的例子如下:

select customers.cust_name, customers.cust_id, count(orders.order_num) as num_ord

from customers left outer join orders on customers.cust_id = orders.cust_id

group by customers.cust_id;  结果如下:

 

十七:组合查询

1:mysql允许执行多个查询,并将结果作为单个查询结果集返回。这些组合查询称为union或组合查询。

2:使用union操作符来组合数条sql查询,比如需要找出价格小于等于5的所有物品的一个列表,而且还需包括供应商1001和1002生产的所有物品,可以使用如下的sql语句:

select vend_id, prod_id, prod_price from products where prod_price <= 5 union

select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002); 结果如下:

上面使用union的sql语句,也可以使用多条where子句完成:

select vend_id, prod_id, prod_price from products where prod_price <= 5 or vend_idin (1001, 1002).

3:union的每个查询必须包含相同的列、表达式或聚集函数。

4:union从查询结果集中自动去除了重复的行,如果需要显示重复的行,可以使用union all,比如:

select vend_id, prod_id, prod_price from products where prod_price <= 5 union all

select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002); 结果如下:

5:再用union组合查询时,只能使用一条order by子句,它必须出现在最后一条select语句之后。它会排序所有select语句返回的所有结果。比如:

select vend_id, prod_id, prod_price from products where prod_price <= 5 union

select vend_id, prod_id, prod_price from products where vend_id in (1001, 1002)

order by vend_id, prod_price; 结果如下:

十八:全文本搜索

1:mysql支持几种基本的数据库引擎,并非所有的引擎支持全文本搜索,比如引擎myisam和innodb,只有myisam引擎支持全文本搜索。全文本搜索比like
和正则表达式具有更强的控制能力。

2:为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断的更新索引。在对表进行适当的设计后,mysql会自动进行所有的索引和重新索引。

3:一般在创建表时启用全文本搜索。create table语句接受fulltext子句,他给出被索引列的一个逗号分隔的列表。比如:

create table productnotes

(

note_id          int                      NOT NULL       AUTO INCREMENT,

prod_id          char(10)            NOT NULL,

note_date      datetime            NOT NULL,

note_text       text                    NULL,

primary key(note_id),

fulltext(note_text)

)

为了进行全文本搜索,mysql根据子句fulltext(note_text)的指示,对它进行索引。这里fulltext索引单个列,如果需要也可以指定多个列。

定义之后,mysql自动维护该索引。在增加、更新和删除行时,索引随之自动更新。

4:在索引之后,使用两个函数match和against进行全文本搜索,其中match指定被搜索的列,against指定要使用的搜索表达式。
比如:

select note_text from productnotes where match(note_text) against(‘rabbit’);

match(note_text)指定mysql针对指定的列进行搜索, against(‘rabbit’)指定词rabbit作为搜索文本。传递给match的值必须与fulltext定义中的相同。如果指定多个列,则必须列出它们,而且次序必须正确。

5:全文本搜索的时候,返回的顺序是按照匹配的良好程度进行排序的数据。尽管两个行都包含rabbit,但是包含词rabbit作为第3个词的行要比作为第20个词的行高。全文本搜索的一个重要部分就是对结果配需,具有较高等级的行先返回。比如:

select note_text match(note_text) against(‘rabbit’) as rank from productnotes; 其中,每个行的rank值如下:

rank列包含全文本搜索计算出的等级值。不包含rabbit行等级为0,确实包含rabbit的两个行每行都有一个等级值。

6:查询扩展用来设法放宽所返回的全文本搜索结果的范围,比如想找出包含anvils的行,还想找出与anvils有关的所有其他行,即使它们不包含anvils。在使用查询扩展时,mysql对数据和索引进行两遍扫描来完成搜索:

a:进行一个基本的全文本搜索,搜索出匹配的所有行;

b:mysql检查这些匹配行并选择所有有用的词;

c:mysql再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词。

比如:select note_text from productnotes where match(note_text) against(‘anvils’ with query expansion); 返回结果如下:

可见,不仅包含anvils的第一行返回了,还返回了与anvils无关的行。

7:mysql支持全文本搜索的另一种形式:布尔方式。布尔方式可以提供:要匹配的词;要排斥的词;排列提示;表达式分组;另外一些内容。

即使没有定义fulltext索引,也可以使用布尔方式,但是比较慢。

8:比如为了匹配包含heavy但不包含任意以rope开始的词的行,可以:

select note_text from productnotes where match(note_text) against(‘heavy –rope*’ inboolean mode);其他布尔方式,查阅其他资料,不再赘述。

《mysql必知必会》笔记2(子查询、联接、组合查询、全文本搜索)的更多相关文章

  1. mysql必知必会

    春节放假没事,找了本电子书mysql必知必会敲了下.用的工具是有道笔记的markdown文档类型. 下面是根据大纲已经敲完的章节,可复制到有道笔记的查看,更美观. # 第一章 了解SQL## 什么是S ...

  2. MySQL必知必会(第4版)整理笔记

    参考书籍: BookName:<SQL必知必会(第4版)> BookName:<Mysql必知必会(第4版)> Author: Ben Forta 说明:本书学习笔记 1.了解 ...

  3. MySQL必知必会1-20章读书笔记

    MySQL备忘 目录 目录 使用MySQL 检索数据 排序检索数据 过滤数据 数据过滤 用通配符进行过滤 用正则表达式进行搜索 创建计算字段 使用数据处理函数 数值处理函数 汇总数据 分组数据 使用子 ...

  4. 《mysql必知必会》读书笔记--存储过程的使用

    以前对mysql的认识与应用只是停留在增删改查的阶段,最近正好在学习mysql相关内容,看了一本书叫做<MySQL必知必会>,看了之后对MySQL的高级用法有了一定的了解.以下内容只当读书 ...

  5. 《MySQL必知必会》学习笔记——前言

    前言 MySQL已经成为世界上最受欢迎的数据库管理系统之一.无论是用在小型开发项目上,还是用来构建那些声名显赫的网站,MySQL都证明了自己是个稳定.可靠.快速.可信的系统,足以胜任任何数据存储业务的 ...

  6. 《MySQL必知必会》学习笔记整理

    简介 此笔记只包含<MySQL必知必会>中部分章节的整理笔记.这部分章节主要是一些在<SQL必知必会>中并未讲解的独属于 MySQL 数据库的一些特性,如正则表达式.全文本搜索 ...

  7. MySQL必知必会复习笔记(1)

    MySQL必知必会笔记(一) MySQL必知必会是一本很优秀的MySQL教程书,并且相当精简,在日常中甚至能当成一本工作手册来查看.本系列笔记记录的是:1.自己记得不够牢的代码:2.自己觉得很重要的代 ...

  8. 《MySQL必知必会》学习笔记

    数据库:数据库是一种以某种有组织的方式存储的数据集合.其本质就是一个容器,通常是一个或者一组文件. 表:表示一种结构化的文件,可用来存储某种特定类型的数据. 模式:描述数据库中特定的表以及整个数据库和 ...

  9. 《MySQL必知必会》读书笔记

    一.了解MySQL      1.什么是数据库?         数据库是一种以某种有组织的方式存储的数据集合.      2.模式(schema):关于数据库和表的布局及特性的信息.      3. ...

随机推荐

  1. SQLSTATE[HY000] [2002] 乱码

    string(59) "SQLSTATE[HY000] [2002] ����Ŀ����������ܾ����޷����ӡ� " 实际意思是:SQLSTATE[HY000] [20 ...

  2. PHP CURL header 设置HOST主机头进行访问并 POST提交數據

    $host = array("Host: act.qzone.qq.com");// 域名不帶http://$data = array(            'aa' => ...

  3. c++设计模式:单例模式

    1.设计思想: 单例模式,顾名思义,即一个类只有一个实例对象.C++一般的方法是将构造函数.拷贝构造函数以及赋值操作符函数声明为private级别,从而阻止用户实例化一个类.那么,如何才能获得该类的对 ...

  4. 搭建php虚拟环境

    参考网址: http://my.oschina.net/u/998304/blog/501363?p={{totalPage}} Box镜像列表: http://www.vagrantbox.es/ ...

  5. 网站被攻击扫描SQL注入的日常记录

    我发了个博客,泄露了域名之后,便有人疯狂的尝试攻击我的站点,奈何我防守做得比较好,直接把网段封了,看到403还锲而不舍,我真是想给他颁奖了 查看ua,发现很多sqlmap的ua,肯定会是被刷了,只是运 ...

  6. hbase phoenix char may not be null

    在使用phoenix做hbase的相关測试的时候.会出现 char may not be null 的错误. 这是因为建表和导入的数据不匹配导致的.主要是char的定义,假如一个字段定义为char类型 ...

  7. Linux 基础命令4进程

    ID和PID的产生 ps( process status) 查看现在的进程 上例中,列出了两个进程,进程 5198 和进程 10129,各自代表命令 bash 和 ps.正如我们所看到的, 默认情况下 ...

  8. linux系统级别的计划任务及其扩展anacrontab

    这个是系统设置好了,清理系统垃圾或者是自动执行某些脚本的系统任务,一般我们做了解就行了,不要更改配置文件是/etc/conrtab SHELL:就是运行计划任务的解释器,默认是bash PATH:执行 ...

  9. Uva116 Unidirectional TSP

    https://odzkskevi.qnssl.com/292ca2c84ab5bd27a2a91d66827dd320?v=1508162936 https://vjudge.net/problem ...

  10. 【cml】wosi-demo

    推荐一个cml项目,https://github.com/Bowen7/wosi-demo 呃呃,运行了项目只能够说开发者好牛逼,数据处理很厉害, 这个是最后的结果,然后要进行效果查看,估计你得等明天 ...