联结:
一种机制,用来在一条SELECT语句中关联表,因此称之为联结。它在数据库中不存在。联结由MySQL根据需要建立,它存在于查询的执行过程中。
创建联结:
(使用WHERE联结)SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;
(保证所有联结都有WHERE子句,不然查询到的结果是两个表的笛卡尔积(第一个表的行乘以第二个表的行))
(使用INNER JOIN ... ON ...联结)
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;
MySQL可以联结多个表,但是联结处理有可能非常耗费资源,因此不要联结不必要的表,联结的表越多,性能下降越厉害。
使用表的别名:
别名除了可以用于列名和计算字段外还可以用于给表起别名。例如: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 = 0.order_num
AND prod_id = 'TNT2';
表别名只在查询执行中使用。与列别名不一样,表别名不返回到客户机。
自联结:
在一张表内部使用联结,自联结比子查询要快。例如完成如下功能:查询商品ID为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';
这里的自联结使用了表的别名,看起来有点赘余,实际上这里的别名是必须要用的,倒不全是因为看起来清晰,更重要的是不让所写的SQL语句产生二义性,所有的计算机技术中最忌讳的东西就是二义性。如果这里使用了表的名字而没有使用别名的话SQL在解释的时候就无法确定到底哪个products语句对应的是哪个products实例化对象。
自然联结:
无论什么时候进行联结,应该至少有一个列出现在不止一个表中(被联结的列)。标准的联结返回所有的数据,甚至相同的列多次出现。自然联结排除多次出现,每个列只返回一次。外联结:
外部联结并不要求联结的两个表的每一条记录在对方表中都有一条匹配的记录(甚至这条记录没有匹配的记录也要保留)如下SQL语句查询所有客户及其订单:
SELECT customers.cust_id, orders.order_num
FROM customers INNER JOIN orders
ON customers.cust_id = orders.cust_id
(返回的结果中没有NULL的值)
如下SQL语句查询所有的客户及其订单(包含NULL的列):
SELECT customers.cust_id, orders.order_num
FROM customers LEFT OUTER JOIN orders
ON customer.cust_id = orders.cust_id
(返回的结果中包含NULL的值)
外联结的语法和内联结的语法很像,只是将INNER JOIN换成了[LEFT,RIGHT]OUTER JOIN。LEFT代表从左边的表中选择所有行,RIGHT表示从右边的表中选择所有行,在MySQL中外联结必须在OUTER JOIN之前使用LIFT或者RIGHT。(注意:MySQL不支持全外联结[左外来凝结和右外联结的并集],但是可以通过左右外联结的病机来模拟实现。)左外联结和右外联结可以通过颠倒FROM和WHERE子句中表的顺序相互转换,两种类型的外部联结究竟使用哪一种纯粹是根据方便而定。
带聚集函数的联结:
聚集函数是用来汇总数据的,也可以和联结一起使用。比如现在要查询所有客户及每个客户所下的订单数,使用联结和COUNT()函数就可以完成此项任务。SELECT customers.cust_id, custormers.cust_name, COUNT(orders.order_num) AS order_count
FROM custormer INNER JOIN orders
ON custormer.cust_id = orders.cust_id
GROUP BY custormer.cust_id;
上述SQL语句中的customers.cust_id中的customers不能省略,如果省略则会产生二义性。
SELECT customer.cust_name, customers.cust_id, COUNT(orders.order_num) AS order_count
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;
使用联结和联结条件
1、注意所使用的联结类型。一般我们使用内部联结,但使用外部联结也是有效的。2、保证使用正确的联结条件,否则将返回不正确的数据。
3、应该总是提供联结条件,否则会得出笛卡尔积。
4、在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做合法,一般也很有用,但应该在一起测试他们前,分别测试每个联结。这将使故障排除更为简单。
组合查询:
MySQL允许执行多个查询,并将结果作为单个查询结果集返回。这些组合查询通常称为并(union)或复合查询。使用组合查询的两个基本情况是:1、在单个查询中从不同的表返回类似结构的数据。
2、对单个表执行多个查询,按单个查询返回数据。
任何具有多个WHERE子句的单条查询完成的工作与具有多个WHERE子句的SELECT语句都可以作为一个组合查询给出。
组合查询的重复行:
组合查询的默认行为是自动从结果集中去除重复行,如果想要返回所有的行则可以使用UNION ALL。对组合查询的结果排序:
在用UNION组合查询时,只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后,对于结果集,不存在用一种方式排序一部分,而又使用另一种方式排序另一部分。因此不允许使用多条ORDER BY子句。全文本搜索:
MySQL支持集中几本的数据库引擎。并非所有的引擎都支持全文本搜索。两个最为常见的引擎为MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。为了使用全文本搜索必须索引被搜索的列,而且要随着数据的改变不断地对表进行适当的设计后,MySQL会自动进行所有的索引和重新索引。在索引之后,SELECT可与Match()和Against()一起使用以实际执行搜索。
进行全文本搜索:
在索引之后,使用两个函数Match()和Against()执行全文本搜索,其中Match()制定被搜索的列,Against()制定要使用的搜索表达式。例如:SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('rabbit');
传递给Match的值必须与FULLTEXT中的值相同,如果有多个值则必须按照正确次序列出来。
全文本搜索的重要部分就是对结果进行排序。具有较高等级的行先返回(因为这些行很可能是你真正想要的行)。因为数据时索引的,所以全文搜索是相当快的。
布尔全文搜索:
MySQL支持全文搜索的另外一种形式,称为布尔方式。以布尔方式,可以提供如下内容的细节:1、要匹配的词
2、要排斥的词
3、排列提示
4、表达式分组
5、另外一些内容。
布尔方式不同于迄今为止使用的全文搜索语法的地方在于,即使没有定义FULLTEXT索引,也可以使用它,但这是一种非常缓慢的操作(其性能将随着数据量的增加而降低)。
全文本布尔操作符:
在布尔方式中,不按等级值降序排序返回的行。
全文本搜索的使用说明:
1、在索引全文本数据时,短词被忽略且从索引中排除。短词定义为那些具有3个或3个以下字符的词(如果需要,这个数字可以更改)。2、MySQL带有一个内建的非用词列表,这些词在索引全文数据时总是被忽略。如果需要,可以覆盖这个表。
3、许多词出现的频率很高,搜索它们没有用处(返回太多结果)。因此,MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用与IN BOOLEAN MODE。
4、如果表中的行数少于3行,则全文本搜索则不返回结果(因为每个词或者出现或者不出现,或者至少出现在50%的行中)。
5、忽略词中的单引号。
6、不具有词分隔符的语言不能恰当地返回全文本搜索结果。
7、如前所述,仅在MyISAM数据库引擎中支持全文搜索。