本文共 5520 字,大约阅读时间需要 18 分钟。
在学习SQL时,查询(query)是最基础的操作。简单查询是从单个数据库表中检索数据的基本操作。然而,SQL还允许嵌套在其他查询中的查询,这被称为子查询(subquery)。
子查询是一种强大的工具,可以帮助我们在复杂的数据检索任务中分解问题。通过使用子查询,我们可以将复杂的逻辑分解为多个简单的查询,并将这些查询的结果结合起来。
在实际应用中,我们经常需要根据某些条件过滤数据。例如,假设我们有以下数据库表:
我们需要列出订购物品“TNT2”的所有客户。具体步骤如下:
检索包含物品“TNT2”的所有订单编号:
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2';
检索具有上一步骤返回的订单编号的所有客户ID:
SELECT cust_id FROM orders WHERE order_num IN (20005, 20007);
检索上一步骤返回的客户ID的客户信息:
SELECT cust_name, cust_contact FROM customers WHERE cust_id IN (10001, 10004);
为了实现上述步骤,可以将子查询嵌套在WHERE子句中:
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'));
子查询还可以用来创建计算字段。例如,我们可以为每个客户显示其订单总数。
从customers表中检索客户列表:
SELECT cust_name, cust_state FROM customers;
为每个客户统计订单数量:
SELECT cust_name, cust_state, (SELECT COUNT(*) FROM orders WHERE orders.cust_id = customers.cust_id) AS orders FROM customers ORDER BY cust_name;
此时,orders字段是由圆括号中的子查询计算得出。子查询会为每个客户执行一次,返回订单总数。
当子查询涉及外部查询的字段时,称为相关子查询(correlated subquery)。在这种情况下,子查询中的字段必须与外部查询中的字段明确相关联。
例如:
SELECT cust_name, cust_contact FROM customers WHERE cust_id = (SELECT cust_id FROM orders WHERE order_num IN (SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'));
如果不明确指定表和字段,可能会导致错误。因此,必须使用明确的字段引用方式:
SELECT cust_name, cust_contact FROM customers WHERE cust_id = orders.cust_id AND orders.order_num IN (SELECT order_num FROM orderitems WHERE prod_id = 'TNT2');
在数据库设计中,关系表的核心思想是将相同的数据存储在不同的表中,以减少数据冗余。例如:
vendors表中的vend_id是products表的外键。
分解数据为多个表可以更有效地存储和处理数据。然而,如何用单一的SELECT语句从多个表中检索数据?这就是联结的作用。
联结是一种机制,用于在一个SELECT语句中关联多个表,返回多个表中的数据。
最简单的联结是等值联结(equijoin),它基于两个表之间的相等测试。例如:
SELECT vend_name, prod_name, prod_price FROM vendors, products WHERE vendors.vend_id = products.vend_id ORDER BY vend_name, prod_name;
此时,vendors和products表通过vend_id字段进行联结。
在联结多个表时,WHERE子句用于指定联结条件。没有WHERE子句,vendors和products表将执行笛卡尔积(cartesian product),返回所有可能的行组合。
内部联结(equijoin)是最常用的联结类型。它要求两个表中的对应字段值相等。可以使用INNER JOIN语法明确指定联结类型:
SELECT vend_name, prod_name, prod_price FROM vendors INNER JOIN products ON vendors.vend_id = products.vend_id;
可以使用多个JOIN关键字将多个表联结在一起。例如:
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;
此时,orderitems表通过prod_id与products表关联,而products表通过vend_id与vendors表关联。
为了简化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 prod_id = 'TNT2';
除了等值联结,还有其他三种类型的联结:
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';
SELECT c.*, o.order_num, o.order_date, oi.prod_id, oi.quantity, oi.item_price 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 prod_id = 'FB';
SELECT customers.cust_id, orders.order_num FROM customers LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id;
聚集函数可以与联结一起使用。例如,统计每个客户的订单数量:
SELECT customers.cust_id, customers.cust_name, COUNT(orders.order_num) AS num_orders FROM customers INNER JOIN orders ON customers.cust_id = orders.cust_id GROUP BY customers.cust_id;
组合查询(Compound Query)是将多个SELECT语句合并为单个结果集的技术。常见的使用场景包括:
UNION操作符用于组合多个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);
此时,UNION关键字将两个SELECT语句的结果合并为单个结果集。
UNION必须由两条或多条SELECT语句组成,语句之间用UNION关键字分隔。SELECT语句必须包含相同的列、表达式或聚集函数。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);
SELECT语句的输出可以使用ORDER BY子句排序。例如:
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;
传统的LIKE和正则表达式匹配有以下限制:
全文本搜索可以解决这些问题。
在创建表时,可以启用全文本搜索:
CREATE TABLE productnotes(note_id int NOT NULL AUTO_INCREMENT, prod_id char NOT NULL, note_date datetime NOT NULL, note_text text NULL, PRIMARY KEY(note_id), FULLTEXT(note_text)) ENGINE=MyISAM;
使用Match()和Against()函数:
SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit'); WITH QUERY EXPANSION可以扩展搜索范围。例如:
SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION); 布尔方式提供更高级的搜索控制:
SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy' IN BOOLEAN MODE); 布尔操作符包括:
| 操作符 | 说明 |
|---|---|
| + | 包含 |
| - | 排除 |
| > | 包含且重要 |
| < | 包含且不重要 |
| () | 定义子表达式 |
| ~ | 取消重要性 |
| * | 词尾通配符 |
| " | 定义短语 |
通过使用全文本搜索,可以高效地检索文本数据,支持复杂的搜索逻辑。
转载地址:http://hyhwz.baihongyu.com/