MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索

  • 联结表
    • 关系
    • 为什么要使用联结
    • 创建联结
      • WHERE子句的重要性
      • 内部联结
      • 联结多个表
  • 创建高级联结
    • 使用表别名
    • 使用不同类型的联结
      • 自联结
      • 自然联结
      • 外部联结
    • 使用带聚集函数的联结
    • 使用联结和联结条件
  • 组合查询
    • 组合查询
    • 创建组合查询
      • 使用UNION
      • UNION规则
      • 包含或取消重复的行
      • 对组合查询结果排序
  • 全文本搜索
    • 理解全文本搜索
    • 使用全文本搜索
      • 启用全文本搜索支持
      • 进行全文本搜索
      • 使用查询扩展
      • 布尔文本搜索
      • 全文本搜索的使用说明

联结表

SQL最强大的功能之一就是能在数据检索查询的执行中联结(join) 表。联结是利用SQL的SELECT能执行的最重要的操作,很好地理解联结 及其语法是学习SQL的一个极为重要的组成部分。

在能够有效地使用联结前,必须了解关系表以及关系数据库设计的 一些基础知识。下面的介绍并不是这个内容的全部知识,但作为入门已 经足够了。

关系

理解关系表的最好方法是来看一个现实世界中的例子。

假如有一个包含产品目录的数据库表,其中每种类别的物品占一行。 对于每种物品要存储的信息包括产品描述和价格,以及生产该产品的供应商信息。

现在,假如有由同一供应商生产的多种物品,那么在何处存储供应 商信息(如,供应商名、地址、联系方法等)呢?将这些数据与产品信 息分开存储的理由如下。

 因为同一供应商生产的每个产品的供应商信息都是相同的,对每 个产品重复此信息既浪费时间又浪费存储空间。
 如果供应商信息改变(例如,供应商搬家或电话号码变动),只需 改动一次即可。
 如果有重复数据(即每种产品都存储供应商信息),很难保证每次 输入该数据的方式都相同。不一致的数据在报表中很难利用。

关键是,相同数据出现多次决不是一件好事,此因素是关系数据库 设计的基础。关系表的设计就是要保证把信息分解成多个表,一类数据 一个表。各表通过某些常用的值(即关系设计中的关系(relational))互 相关联。
在这个例子中,可建立两个表,一个存储供应商信息,另一个存储 产品信息。vendors表包含所有供应商信息,每个供应商占一行,每个供 应商具有唯一的标识。此标识称为主键(primary key)(在第1章中首次 提到),可以是供应商ID或任何其他唯一值。

products表只存储产品信息,它除了存储供应商ID(vendors表的主 键)外不存储其他供应商信息。vendors表的主键又叫作products的外键, 它将vendors表与products表关联,利用供应商ID能从vendors表中找出 相应供应商的详细信息。

外键(foreignkey) 外键为某个表中的一列,它包含另一个表 的主键值,定义了两个表之间的关系。
这样做的好处如下:

 供应商信息不重复,从而不浪费时间和空间;
 如果供应商信息变动,可以只更新vendors表中的单个记录,相
关表中的数据不用改动;
 由于数据无重复,显然数据是一致的,这使得处理数据更简单。

总之,关系数据可以有效地存储和方便地处理。因此,关系数据库 的可伸缩性远比非关系数据库要好。

可伸缩性(scale) 能够适应不断增加的工作量而不失败。设 计良好的数据库或应用程序称之为可伸缩性好(scale well)。

为什么要使用联结

正如所述,分解数据为多个表能更有效地存储,更方便地处理,并
且具有更大的可伸缩性。但这些好处是有代价的。

如果数据存储在多个表中,怎样用单条SELECT语句检索出数据?

答案是使用联结。简单地说,联结是一种机制,用来在一条SELECT 语句中关联表,因此称之为联结。使用特殊的语法,可以联结多个表返 回一组输出,联结在运行时关联表中正确的行。

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第1张图片

创建联结

联结的创建非常简单,规定要联结的所有表以及它们如何关联即可。 请看下面的例子:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第2张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第3张图片

WHERE子句的重要性

利用WHERE子句建立联结关系似乎有点奇怪,但实际上,有一个很充 分的理由。请记住,在一条SELECT语句中联结几个表时,相应的关系是 在运行中构造的。在数据库表的定义中不存在能指示MySQL如何对表进 行联结的东西。你必须自己做这件事情。在联结两个表时,你实际上做 的是将第一个表中的每一行与第二个表中的每一行配对。WHERE子句作为 过滤条件,它只包含那些匹配给定条件(这里是联结条件)的行。没有WHERE子句,第一个表中的每个行将与第二个表中的每个行配对,而不管它们逻辑上是否可以配在一起。

笛卡儿积(cartesian product) 由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘 以第二个表中的行数。

为理解这一点,请看下面的SELECT语句及其输出:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第4张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第5张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第6张图片

内部联结

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第7张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第8张图片

联结多个表

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第9张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第10张图片

创建高级联结

本章将讲解另外一些联结类型(包括它们的含义和使用方法),介 绍如何对被联结的表使用表别名和聚集函数。

使用表别名

第10章中介绍了如何使用别名引用被检索的表列。给列起别名的语
法如下:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第11张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第12张图片

使用不同类型的联结

迄今为止,我们使用的只是称为内部联结或等值联结(equijoin)的简
单联结。现在来看3种其他联结,它们分别是自联结、自然联结和外部联结。

自联结

如前所述,使用表别名的主要原因之一是能在单条SELECT语句中不 止一次引用相同的表。下面举一个例子。

假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物 品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到 生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。 下面是解决此问题的一种方法:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第13张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第14张图片
为解决此问题,使用了表别名。products的第一次出现为别名p1, 第二次出现为别名p2。现在可以将这些别名用作表名。例如,SELECT语 句使用p1前缀明确地给出所需列的全名。如果不这样,MySQL将返回错 误,因为分别存在两个名为prod_id、prod_name的列。MySQL不知道想 要的是哪一个列(即使它们事实上是同一个列)。WHERE(通过匹配p1中 的vend_id和p2中的vend_id)首先联结两个表,然后按第二个表中的 prod_id过滤数据,返回所需的数据。
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第15张图片

自然联结

无论何时对表进行联结,应该至少有一个列出现在不止一个表中(被联结的列)。标准的联结(前一章中介绍的内部联结)返回所有数据,甚 至相同的列多次出现。自然联结排除多次出现,使每个列只返回一次。

怎样完成这项工作呢?答案是,系统不完成这项工作,由你自己完成它。自然联结是这样一种联结,其中你只能选择那些唯一的列。这一 般是通过对表使用通配符(SELECT *),对所有其他表的列使用明确的子 集来完成的。下面举一个例子:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第16张图片
事实上,迄今为止我们建立的每个内部联结都是自然联结,很可能 我们永远都不会用到不是自然联结的内部联结。

外部联结

许多联结将一个表中的行与另一个表中的行相关联。但有时候会需
要包含没有关联行的那些行。例如,可能需要使用联结来完成以下工作:

 对每个客户下了多少订单进行计数,包括那些至今尚未下订单的 客户;
 列出所有产品以及订购数量,包括没有人订购的产品;
 计算平均销售规模,包括那些至今尚未下订单的客户。

在上述例子中,联结包含了那些在相关表中没有关联行的行。这种 类型的联结称为外部联结。

下面的SELECT语句给出一个简单的内部联结。它检索所有客户及其订单:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第17张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第18张图片
在这里插入图片描述

使用带聚集函数的联结

正如第12章所述,聚集函数用来汇总数据。虽然至今为止聚集函数
的所有例子只是从单个表汇总数据,但这些函数也可以与联结一起使用。

为说明这一点,请看一个例子。如果要检索所有客户及每个客户所
下的订单数,下面使用了COUNT()函数的代码可完成此工作:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第19张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第20张图片

使用联结和联结条件

在总结关于联结的这两章前,有必要汇总一下关于联结及其使用的
某些要点。

 注意所使用的联结类型。一般我们使用内部联结,但使用外部联 结也是有效的。
 保证使用正确的联结条件,否则将返回不正确的数据。
 应该总是提供联结条件,否则会得出笛卡儿积。
 在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一 起测试它们前,分别测试每个联结。这将使故障排除更为简单。

组合查询

本章讲述如何利用UNION操作符将多条SELECT语句组合成一个结果集。

组合查询

多数SQL查询都只包含从一个或多个表中返回数据的单条SELECT语句。MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个 查询结果集返回。这些组合查询通常称为并(union)或复合查询(compound query)。

有两种基本情况,其中需要使用组合查询:

 在单个查询中从不同的表返回类似结构的数据;

 对单个表执行多个查询,按单个查询返回数据。
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第21张图片

创建组合查询

可用UNION操作符来组合数条SQL查询。利用UNION,可给出多条SELECT语句,将它们的结果组合成单个结果集。

使用UNION

UNION的使用很简单。所需做的只是给出每条SELECT语句,在各条语 句之间放上关键字UNION。

举一个例子,假如需要价格小于等于5的所有物品的一个列表,而且 还想包括供应商1001和1002生产的所有物品(不考虑价格)。当然,可以 利用WHERE子句来完成此工作,不过这次我们将使用UNION。

正如所述,创建UNION涉及编写多条SELECT语句。首先来看单条语句:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第22张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第23张图片

UNION规则

正如所见,并是非常容易使用的。但在进行并时有几条规则需要注意。

 UNION必须由两条或两条以上的SELECT语句组成,语句之间用关 键字UNION分隔(因此,如果组合4条SELECT语句,将要使用3个 UNION关键字)。

 UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。

 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以
隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。 如果遵守了这些基本规则或限制,则可以将并用于任何数据检索任务。

包含或取消重复的行

请返回到17.2.1节,考察一下所用的样例SELECT语句。我们注意到, 在分别执行时,第一条SELECT语句返回4行,第二条SELECT语句返回5行。 但在用UNION组合两条SELECT语句后,只返回了8行而不是9行。

UNION从查询结果集中自动去除了重复的行(换句话说,它的行为与单条SELECT语句中使用多个WHERE子句条件一样)。因为供应商1002生产的一种物品的价格也低于5,所以两条SELECT语句都返回该行。在使用 UNION时,重复的行被自动取消。

这是UNION的默认行为,但是如果需要,可以改变它。事实上,如果想返回所有匹配行,可使用UNION ALL而不是UNION。

请看下面的例子:

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第24张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第25张图片

对组合查询结果排序

SELECT语句的输出用ORDER BY子句排序。在用UNION组合查询时,只 能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。对 于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一 部分的情况,因此不允许使用多条ORDER BY子句。

下面的例子排序前面UNION返回的结果:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第26张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第27张图片

全文本搜索

理解全文本搜索

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第28张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第29张图片

使用全文本搜索

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

在索引之后,SELECT可与Match()和Against()一起使用以实际执行搜索。

启用全文本搜索支持

一般在创建表时启用全文本搜索。CREATE TABLE语句(第21章中介
绍)接受FULLTEXT子句,它给出被索引列的一个逗号分隔的列表。 下面的CREATE语句演示了FULLTEXT子句的使用:
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第30张图片

进行全文本搜索

在索引之后,使用两个函数Match()和Against()执行全文本搜索,
其中Match()指定被搜索的列,Against()指定要使用的搜索表达式。

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第31张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第32张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第33张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第34张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第35张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第36张图片

使用查询扩展

查询扩展用来设法放宽所返回的全文本搜索结果的范围。考虑下面 的情况。你想找出所有提到anvils的注释。只有一个注释包含词anvils, 但你还想找出可能与你的搜索有关的所有其他行,即使它们不包含词anvils。

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第37张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第38张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第39张图片

布尔文本搜索

MySQL支持全文本搜索的另外一种形式,称为布尔方式(boolean
mode)。以布尔方式,可以提供关于如下内容的细节:
 要匹配的词;
 要排斥的词(如果某行包含这个词,则不返回该行,即使它包含
其他指定的词也是如此);
 排列提示(指定某些词比其他词更重要,更重要的词等级更高);  表达式分组;
 另外一些内容。
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第40张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第41张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第42张图片
MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第43张图片
排列而不排序 在布尔方式中,不按等级值降序排序返回的行。

全文本搜索的使用说明

在结束本章之前,给出关于全文本搜索的某些重要的说明。

 在索引全文本数据时,短词被忽略且从索引中排除。短词定义为 那些具有3个或3个以下字符的词(如果需要,这个数目可以更改)。

 MySQL带有一个内建的非用词(stopword)列表,这些词在索引
全文本数据时总是被忽略。如果需要,可以覆盖这个列表(请参
阅MySQL文档以了解如何完成此工作)。

 许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。
因此,MySQL规定了一条50%规则,如果一个词出现在50%以上 的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE。

 如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词 或者不出现,或者至少出现在50%的行中)。

 忽略词中的单引号。例如,don’t索引为dont。

 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文
本搜索结果。

 如前所述,仅在MyISAM数据库引擎中支持全文本搜索。

MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索_第44张图片

你可能感兴趣的:(MySQL 第15章、第16章、第17章、第18章 联结表、创建高级联结、组合查询、全文本搜索)