十四:使用子查询

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. Leetcode82. Remove Duplicates from Sorted List II删除排序链表中的重复元素2

    给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4->4->5 输出: 1-&g ...

  2. mysql导出数据库某些表的数据

    # 导出数据,一般从从库导出,减少主库的压力.mysqldump -hhostname -P3306 --single-transaction --master-data= database_name ...

  3. leetcode 321 Create Max Number

    leetcode 321 Create Max Number greedy的方法,由于有两个数组,我们很自然的想到从数组1中选i个数,数组2中选k-i个数,这样我们只需要遍历max(0, k-数组2长 ...

  4. Django项目:CRM(客户关系管理系统)--39--31PerfectCRM实现King_admin编辑多对多限制

    readonly_fields = ('qq', 'consultant','tags',) # 不可修改 # forms.py # ————————19PerfectCRM实现King_admin数 ...

  5. [转]文件file属性详解

    不能直接访问用户计算机中的文件,一直都是Web应用开发中的一大障碍.2000年以前,处理文件的唯一方式就是在表单中加入<input type="file">字段,仅此而 ...

  6. 做移动应用使用地图API时需要注意的问题

    最近在做一个基于地点提醒的移动应用,当初考虑大家都心知肚明的原因,谨慎的选择了百度地图,现在想想其实完全没有必要,好的应用本来就不分国界的,最后可能还是得换回Google地图.毕竟Google地图在技 ...

  7. ubuntu 软件的更新及解决软件中心自己无法打开

    sudo apt-get update sudo apt-get dist-upgrade sudo apt-get install --reinstall software-center

  8. JAVA读取文件操作时路径的斜杠问题

    java中的路径一般用"/"windows中的路径用"\"linux,unix中的路径一般用"/"其中java中"/"等 ...

  9. PYTHON网络爬虫与信息提取[BeautifulSoup](单元四)

    1 简介 from bs4 import BeautifulSoup soup=BeautifulSoup(<p>data</p>,'html.parser') 2 基本元素 ...

  10. 2019.9.27 csp-s模拟测试53 反思总结

    这个起名方式居然还有后续?! 为什么起名不是连续的?! T1想了半天,搞出来了,结果数组开小[其实是没注意范围].T2概率期望直接跳,后来翻回来写发现自己整个理解错了期望的含义[何].T3错误想到赛道 ...