[root@mastera0 ~]# yum install -y wget vim net-tools unzip [root@mastera0 ~]# wget http://classroom.example.com/content/MYSQL/04-othersmysql_scripts.zip [root@mastera0 ~]# ls anaconda-ks.cfg mysql_scripts.zip [root@mastera0 ~]# unzip mysql_scripts.zip [root@mastera0 ~]# ls anaconda-ks.cfg create.sql mysql_scripts.zip populate.sql [root@mastera0 ~]# mysql -uroot -puplooking Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 4 Server version: 5.5.44-MariaDB MariaDB Server
Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec)
MariaDB [(none)]> exit Bye # 导入create.sql到test库,将会创建一些表 [root@mastera0 ~]# mysql -uroot -puplooking test < create.sql [root@mastera0 ~]# mysql -uroot -puplooking -e "show tables from test"; +----------------+ | Tables_in_test | +----------------+ | customers | | orderitems | | orders | | productnotes | | products | | vendors | +----------------+ # 导入populate.sql到test库,将会向表中新增数据 [root@mastera0 ~]# mysql -uroot -puplooking test < populate.sql [root@mastera0 ~]# mysql -uroot -puplooking -e "select * from test.vendors"; +---------+----------------+-----------------+-------------+------------+----------+--------------+ | vend_id | vend_name | vend_address | vend_city | vend_state | vend_zip | vend_country | +---------+----------------+-----------------+-------------+------------+----------+--------------+ | 1001 | Anvils R Us | 123 Main Street | Southfield | MI | 48075 | USA | | 1002 | LT Supplies | 500 Park Street | Anytown | OH | 44333 | USA | | 1003 | ACME | 555 High Street | Los Angeles | CA | 90046 | USA | | 1004 | Furball Inc. | 1000 5th Avenue | New York | NY | 11111 | USA | | 1005 | Jet Set | 42 Galaxy Road | London | NULL | N16 6PS | England | | 1006 | Jouets Et Ours | 1 Rue Amusement | Paris | NULL | 45678 | France | +---------+----------------+-----------------+-------------+------------+----------+--------------+
[root@mastera0 ~]# mysql -uroot -puplooking Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 15 Server version: 5.5.44-MariaDB MariaDB Server
Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. # 查询所有的数据库 MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec) # 使用test库 MariaDB [(none)]> use test; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A
区分大小写和排序顺序 在对文本性的数据进行排序时,A与a相同吗?a位于B之前还是位于Z之后?这些问题不是理论问题,其答案取决于数据库如何设置。在字典(dictionary)排序顺序中, A被视为与a相同,这是MySQL(和大多数数据库管理系统)的默认行为。但是,许多数据库管理员能够在需要时改变这种行为(如果你的数据库包含大量外语字符,可能必须这样做)。这里,关键的问题是,如果确实需要改变这种排序顺序,用简单的 ORDER BY 子句做不到。你必须请求数据库管理员的帮助。
利用SELECT语句从products表中检索出最昂贵物品价格prod_price
MariaDB [test]> select prod_price from products order by prod_price desc limit 1; +------------+ | prod_price | +------------+ | 55.00 | +------------+ 1 row in set (0.00 sec)
MariaDB [test]> select prod_price from products order by prod_price desc limit 0,1; +------------+ | prod_price | +------------+ | 55.00 | +------------+ 1 row in set (0.00 sec)
MariaDB [test]> select prod_price from products order by prod_price desc limit 1 offset 0; +------------+ | prod_price | +------------+ | 55.00 | +------------+ 1 row in set (0.00 sec)
ORDER BY 子句的位置 在给出 ORDER BY 子句时,应该保证它位于 FROM 子句之后。如果使用 LIMIT ,它必须位于 ORDER BY之后。使用子句的次序不对将产生错误消息。
MariaDB [test]> select prod_price from products limit 1 order by prod_price desc; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'order by prod_price desc' at line 1
小结
本章学习了如何用 SELECT 语句的 ORDER BY 子句对检索出的数据进行排序。这个子句必须位于 FROM 子句之后,必须是 SELECT 语句中的最后一条子句。可根据需要,利用它在一个或多个列上对数据进行排序。
WHERE 子句的位置 在同时使用 ORDER BY 和 WHERE 子句时,应该让 ORDER BY 位于 WHERE 之后,否则将会产生错误。
MariaDB [test]> select prod_name,prod_price from products where prod_name like "T%" order by prod_price desc; +----------------+------------+ | prod_name | prod_price | +----------------+------------+ | TNT (5 sticks) | 10.00 | | TNT (1 stick) | 2.50 | +----------------+------------+ 2 rows in set (0.01 sec)
MariaDB [test]> select prod_name,prod_price from products order by prod_price desc where prod_name like "T%"; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'where prod_name like "T%"' at line 1
WHERE 子句操作符
我们在关于相等的测试时看到了第一个 WHERE 子句,它确定一个列是否包含特定的值。MySQL支持下表列出的所有条件操作符。
请看上面的结果。返回的行中有两行价格小于10美元,显然,返回的行未按预期的进行过滤。为什么会这样呢?原因在于计算的次序。SQL(像多数语言一样)在处理 OR 操作符前,优先处理 AND 操作符。当SQL看到上述 WHERE 子句时,它理解为由供应商 1003 制造的任何价格为10美元(含)以上的产品,或者由供应商 1002 制造的任何产品,而不管其价格如何。换句话说,由于 AND 在计算次序中优先级更高,操作符被错误地组合了。
此问题的解决方法是使用圆括号明确地分组相应的操作符。请看下面的 SELECT 语句及输出:
MariaDB [test]> select prod_name,prod_price,vend_id from products where (vend_id=1002 or vend_id=1003) and prod_price >=10; +----------------+------------+---------+ | prod_name | prod_price | vend_id | +----------------+------------+---------+ | Detonator | 13.00 | 1003 | | Bird seed | 10.00 | 1003 | | Safe | 50.00 | 1003 | | TNT (5 sticks) | 10.00 | 1003 | +----------------+------------+---------+ 4 rows in set (0.00 sec)
其他方法:
MariaDB [test]> select prod_name,prod_price,vend_id from products where prod_price >= 10 and vend_id=1002 or prod_price >=10 and vend_id=1003 ; +----------------+------------+---------+ | prod_name | prod_price | vend_id | +----------------+------------+---------+ | Detonator | 13.00 | 1003 | | Bird seed | 10.00 | 1003 | | Safe | 50.00 | 1003 | | TNT (5 sticks) | 10.00 | 1003 | +----------------+------------+---------+ 4 rows in set (0.00 sec)
在WHERE子句中使用圆括号 任何时候使用具有 AND 和 OR 操作符的 WHERE 子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认计算次序,即使它确实是你想要的东西也是如此。使用圆括号没有什么坏处,它能消除歧义。
IN 操作符
圆括号在 WHERE 子句中还有另外一种用法。 IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。 IN 取合法值的由逗号分隔的清单,全都括在圆括号中。
MariaDB [test]> select concat(rtrim(vend_name),' (',rtrim(vend_country),')') as vend_title from vendors order by vend_name; +-------------------------+ | vend_title | +-------------------------+ | ACME (USA) | | Anvils R Us (USA) | | Furball Inc. (USA) | | Jet Set (England) | | Jouets Et Ours (France) | | LT Supplies (USA) | +-------------------------+ 6 rows in set (0.00 sec)
MariaDB [test]> select vend_name,upper(vend_name) as vend_name_upcase from vendors order by vend_name; +----------------+------------------+ | vend_name | vend_name_upcase | +----------------+------------------+ | ACME | ACME | | Anvils R Us | ANVILS R US | | Furball Inc. | FURBALL INC. | | Jet Set | JET SET | | Jouets Et Ours | JOUETS ET OURS | | LT Supplies | LT SUPPLIES | +----------------+------------------+ 6 rows in set (0.00 sec)
customers 表中有一个顾客 Coyote Inc. ,其联系名为Y Lee。但如果这是输入错误,此联系名实际应该是 Y Lie ,怎么办?显然,按正确的联系名搜索不会返回数据。
MariaDB [test]> select cust_name,cust_contact from customers where cust_contact = 'Y Lie'; Empty set (0.00 sec)
MariaDB [test]> select cust_name,cust_contact from customers where soundex(cust_contact) = soundex('Y Lie'); +-------------+--------------+ | cust_name | cust_contact | +-------------+--------------+ | Coyote Inc. | Y Lee | +-------------+--------------+ 1 row in set (0.00 sec)
这是重新复习用 WHERE 进行数据过滤的一个好时机。迄今为止,我们都是用比较数值和文本的 WHERE 子句过滤数据,但数据经常需要用日期进行过滤。用日期进行过滤需要注意一些别的问题和使用特殊的MySQL函数。
首先需要注意的是MySQL使用的日期格式。无论你什么时候指定一个日期,不管是插入或更新表值还是用 WHERE 子句进行过滤,日期必须为格式yyyy-mm-dd。因此,2005年9月1日,给出为2005-09-01。虽然其他的日期格式可能也行,但这是首选的日期格式,因为它排除了多义性(如,04/05/06是2006年5月4日或2006年4月5日或2004年5月6日或……)。
MariaDB [test]> select avg(prod_price) as avg_price from products where vend_id=1003; +-----------+ | avg_price | +-----------+ | 13.212857 | +-----------+ 1 row in set (0.00 sec)
使用 ROLLUP 使用 WITH ROLLUP 关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值,如下所示:
MariaDB [test]> select vend_id,count(vend_id) as num_prods from products group by vend_id with rollup; +---------+-----------+ | vend_id | num_prods | +---------+-----------+ | 1001 | 3 | | 1002 | 2 | | 1003 | 7 | | 1005 | 2 | | NULL | 14 | +---------+-----------+ 5 rows in set (0.00 sec)
过滤分组
除了能用 GROUP BY 分组数据外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组。例如,可能想要列出至少有两个订单的所有 113顾客。为得出这种数据,必须基于完整的分组而不是个别的行进行过滤。。但是,在这个例我们已经看到了 WHERE 子句的作用(第6章中引入)子中 WHERE 不能完成任务,因为 WHERE 过滤指定的是行而不是分组。事实上, WHERE 没有分组的概念。那么,不使用 WHERE 使用什么呢?MySQL为此目的提供了另外的子句,那就是 HAVING 子句。 HAVING 非常类似于 WHERE 。事实上,目前为止所学过的所有类型的 WHERE 子句都可以用 HAVING 来替代。唯一的差别是WHERE 过滤行,而 HAVING 过滤分组。HAVING 支持所有 WHERE 操作符在第6章和第7章中,我们学习了 WHERE 子句的条件(包括通配符条件和带多个操作符的子句)。所学过的有关 WHERE 的所有这些技术和选项都适用于HAVING 。它们的句法是相同的,只是关键字有差别。那么,怎么过滤分组呢?请看以下的例子:
过滤两个以上的订单的那些分组
MariaDB [test]> select cust_id,count(*) as orders from orders group by cust_id; +---------+--------+ | cust_id | orders | +---------+--------+ | 10001 | 2 | | 10003 | 1 | | 10004 | 1 | | 10005 | 1 | +---------+--------+ 4 rows in set (0.00 sec)
MariaDB [test]> select cust_id,count(*) as orders from orders group by cust_id having count(*) >= 2; +---------+--------+ | cust_id | orders | +---------+--------+ | 10001 | 2 | +---------+--------+ 1 row in set (0.00 sec)
正如所见,这里 WHERE 子句不起作用,因为过滤是基于分组聚集值而不是特定行值的。
HAVING 和 WHERE 的差别 这里有另一种理解方法, WHERE 在数据分组前进行过滤, HAVING 在数据分组后进行过滤。这是一个重要的区别, WHERE 排除的行不包括在分组中。这可能会改变计算值,从而影响 HAVING 子句中基于这些值过滤掉的分组。
那么,有没有在一条语句中同时使用 WHERE 和 HAVING 子句的需要呢?事实上,确实有。假如想进一步过滤上面的语句,使它返回过去12个月内具有两个以上订单的顾客。为达到这一点,可增加一条 WHERE 子句,过滤出过去12个月内下过的订单。然后再增加 HAVING 子句过滤出具有两个以上订单的分组。
为更好地理解,请看下面的例子。
列出具有 2 个(含)以上、价格为 10 (含)以上的产品的供应商:
MariaDB [test]> select vend_id,count(vend_id) from products where prod_price >= 10 group by vend_id ; +---------+----------------+ | vend_id | count(vend_id) | +---------+----------------+ | 1001 | 1 | | 1003 | 4 | | 1005 | 2 | +---------+----------------+ 3 rows in set (0.00 sec)
MariaDB [test]> select vend_id,count(vend_id) from products where prod_price >= 10 group by vend_id having count(vend_id) >= 2 ; +---------+----------------+ | vend_id | count(vend_id) | +---------+----------------+ | 1003 | 4 | | 1005 | 2 | +---------+----------------+ 2 rows in set (0.01 sec)
这条语句中,使用了聚集函数的基本 SELECT ,它与前面的例子很相像。 WHERE 子句过滤所有 prod_price 至少为 10 的行。然后按 vend_id分组数据, HAVING 子句过滤计数为 2 或 2 以上的分组。如果没有 WHERE 子句,将会多检索出两行(供应商 1002 ,销售的所有产品价格都在 10 以下;供应商 1001 ,销售3个产品,但只有一个产品的价格大于等于 10 ):
MariaDB [test]> select vend_id,count(vend_id) from products group by vend_id having count(vend_id) >= 2 ; +---------+----------------+ | vend_id | count(vend_id) | +---------+----------------+ | 1001 | 3 | | 1002 | 2 | | 1003 | 7 | | 1005 | 2 | +---------+----------------+ 4 rows in set (0.00 sec)
分组和排序
虽然 GROUP BY 和 ORDER BY 经常完成相同的工作,但它们是非常不同的。
下表汇总了它们之间的差别
ORDER BY
GROUP BY
排序产生的输出
分组行。但输出可能不是分组的顺序
任意列都可以使用(甚至非选择的列也可以使用)
只可能使用选择列或表达式列,而且必须使用每个选择列表达式
不一定需要
如果与聚集函数一起使用列(或表达式),则必须使用
表中列出的第一项差别极为重要。我们经常发现用 GROUP BY 分组的数据确实是以分组顺序输出的。但情况并不总是这样,它并不是SQL规范所要求的。此外,用户也可能会要求以不同于分组的顺序排序。仅因为你以某种方式分组数据(获得特定的分组聚集值),并不表示你需要以相同的方式排序输出。应该提供明确的 ORDER BY 子句,即使其效果等同于 GROUP BY 子句也是如此。
不要忘记 ORDER BY 一般在使用 GROUP BY 子句时,应该也给出 ORDER BY 子句。这是保证数据正确排序的唯一方法。千万不要仅依赖 GROUP BY 排序数据。
为说明 GROUP BY 和 ORDER BY 的使用方法,请看一个例子。下面的SELECT 语句类似于前面那些例子。
上述每个步骤都可以单独作为一个查询来执行。可以把一条 SELECT语句返回的结果用于另一条 SELECT 语句的 WHERE 子句。也可以使用子查询来把3个查询组合成一条语句
MariaDB [test]> select order_num from orderitems where prod_id='TNT2'; +-----------+ | order_num | +-----------+ | 20005 | | 20007 | +-----------+ 2 rows in set (0.00 sec)
MariaDB [test]> select cust_id from orders where order_num = 20005 or order_num = 20007; +---------+ | cust_id | +---------+ | 10001 | | 10004 | +---------+ 2 rows in set (0.00 sec)
MariaDB [test]> select cust_name from customers where cust_id in (10001,10004); +----------------+ | cust_name | +----------------+ | Coyote Inc. | | Yosemite Place | +----------------+ 2 rows in set (0.00 sec)
MariaDB [test]> select cust_name from customers where cust_id in > ( > select cust_id from orders where order_num in > (select order_num from orderitems where prod_id='TNT2') > ); +----------------+ | cust_name | +----------------+ | Coyote Inc. | | Yosemite Place | +----------------+ 2 rows in set (0.00 sec)
可见,在 WHERE 子句中使用子查询能够编写出功能很强并且很灵活的SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于性能的限制,不能嵌套太多的子查询。
列必须匹配 在 WHERE 子句中使用子查询(如这里所示),应该保证 SELECT 语句具有与 WHERE 子句中相同数目的列。通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。
正如前两章所述,可使用 SELECT COUNT ( *) 对表中的行进行计数,并且通过提供一条 WHERE 子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。
MariaDB [test]> select cust_name,cust_state,(select count(*) from orders where orders.cust_id=customers.cust_id) as orders from customers order by cust_name; +----------------+------------+--------+ | cust_name | cust_state | orders | +----------------+------------+--------+ | Coyote Inc. | MI | 2 | | E Fudd | IL | 1 | | Mouse House | OH | 0 | | Wascals | IN | 1 | | Yosemite Place | AZ | 1 | +----------------+------------+--------+ 5 rows in set (0.00 sec)
MariaDB [test]> select cust_name,cust_state,(select count(*) from orders where cust_id=cust_id) as orders from customers order by cust_name;+----------------+------------+--------+ | cust_name | cust_state | orders | +----------------+------------+--------+ | Coyote Inc. | MI | 5 | | E Fudd | IL | 5 | | Mouse House | OH | 5 | | Wascals | IN | 5 | | Yosemite Place | AZ | 5 | +----------------+------------+--------+ 5 rows in set (0.00 sec)
利用 WHERE 子句建立联结关系似乎有点奇怪,但实际上,有一个很充分的理由。请记住,在一条 SELECT 语句中联结几个表时,相应的关系是在运行中构造的。在数据库表的定义中不存在能指示MySQL如何对表进行联结的东西。你必须自己做这件事情。在联结两个表时,你实际上做的是将第一个表中的每一行与第二个表中的每一行配对。 WHERE 子句作为过滤条件,它只包含那些匹配给定条件(这里是联结条件)的行。没有WHERE 子句,第一个表中的每个行将与第二个表中的每个行配对,而不管它们逻辑上是否可以配在一起。
MariaDB [test]> select cust_name from customers where cust_id in (select cust_id from orders where order_num in (select order_num from orderitems where prod_id='TNT2')); +----------------+ | cust_name | +----------------+ | Coyote Inc. | | Yosemite Place | +----------------+ 2 rows in set (0.00 sec)
子查询并不总是执行复杂 SELECT 操作的最有效的方法,下面是使用联结的相同查询:
MariaDB [test]> select cust_name from customers where cust_id in (select cust_id from orders where order_num in (select order_num from orderitems where prod_id='TNT2')); +----------------+ | cust_name | +----------------+ | Coyote Inc. | | Yosemite Place | +----------------+ 2 rows in set (0.00 sec)
这个查询中返回数据需要使用3个表。但这里我们没有在嵌套子查询中使用它们,而是使用了两个联结。这里有3个 WHERE 子句条件。前两个关联联结中的表,后一个过滤产品 TNT2的数据。
MariaDB [test]> select concat(rtrim(vend_name),'(',rtrim(vend_country),')') as vend_tile from vendors order by vend_name; +------------------------+ | vend_tile | +------------------------+ | ACME(USA) | | Anvils R Us(USA) | | Furball Inc.(USA) | | Jet Set(England) | | Jouets Et Ours(France) | | LT Supplies(USA) | +------------------------+ 6 rows in set (0.00 sec)
别名除了用于列名和计算字段外, SQL还允许给表名起别名。这样做有两个主要理由:
缩短SQL语句;
允许在单条 SELECT 语句中多次使用相同的表。
请看下面的 SELECT 语句。它与前一章的例子中所用的语句基本相同, 但改成了使用别名:
返回订购产品 TNT2 的客户列表
MariaDB [test]> 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'; +----------------+--------------+ | cust_name | cust_contact | +----------------+--------------+ | Coyote Inc. | Y Lee | | Yosemite Place | Y Sam | +----------------+--------------+ 2 rows in set (0.00 sec)
可以看到, FROM 子句中3个表全都具有别名。 customers AS c 建立 c 作为 customers 的别名,等等。这使得能使用省写的 c 而不是全名 customers 。在此例子中,表别名只用于 WHERE 子句。但是,表别名不仅能用于 WHERE 子句,它还可以用于 SELECT 的列表、 ORDER BY 子句以及语句的其他部分。
MariaDB [test]> 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'; +---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+-----------+---------------------+---------+----------+------------+ | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | order_num | order_date | prod_id | quantity | item_price | +---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+-----------+---------------------+---------+----------+------------+ | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | 20005 | 2005-09-01 00:00:00 | FB | 1 | 10.00 | | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | 20009 | 2005-10-08 00:00:00 | FB | 1 | 10.00 | +---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+-----------+---------------------+---------+----------+------------+ 2 rows in set (0.00 sec)
MariaDB [test]> select * from customers; +---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 10002 | Mouse House | 333 Fromage Lane | Columbus | OH | 43333 | USA | Jerry Mouse | NULL | | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | +---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 5 rows in set (0.00 sec)
MariaDB [test]> select * from orders; +-----------+---------------------+---------+ | order_num | order_date | cust_id | +-----------+---------------------+---------+ | 20005 | 2005-09-01 00:00:00 | 10001 | | 20006 | 2005-09-12 00:00:00 | 10003 | | 20007 | 2005-09-30 00:00:00 | 10004 | | 20008 | 2005-10-03 00:00:00 | 10005 | | 20009 | 2005-10-08 00:00:00 | 10001 | +-----------+---------------------+---------+ 5 rows in set (0.00 sec) # 内部联结或等值联结(equijoin)的简单联结 MariaDB [test]> select orders.*,customers.* from customers inner join orders on customers.cust_id = orders.cust_id; +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | order_num | order_date | cust_id | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 20005 | 2005-09-01 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20006 | 2005-09-12 00:00:00 | 10003 | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 20007 | 2005-09-30 00:00:00 | 10004 | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 20008 | 2005-10-03 00:00:00 | 10005 | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | | 20009 | 2005-10-08 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 5 rows in set (0.00 sec) # 内部联结或等值联结(equijoin)的简单联结 MariaDB [test]> select orders.*,customers.* from orders inner join customers on customers.cust_id = orders.cust_id; +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | order_num | order_date | cust_id | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 20005 | 2005-09-01 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20009 | 2005-10-08 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20006 | 2005-09-12 00:00:00 | 10003 | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 20007 | 2005-09-30 00:00:00 | 10004 | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 20008 | 2005-10-03 00:00:00 | 10005 | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 5 rows in set (0.00 sec) # 左外部联结 MariaDB [test]> select orders.*,customers.* from customers left outer join orders on customers.cust_id = orders.cust_id; +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | order_num | order_date | cust_id | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 20005 | 2005-09-01 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20006 | 2005-09-12 00:00:00 | 10003 | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 20007 | 2005-09-30 00:00:00 | 10004 | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 20008 | 2005-10-03 00:00:00 | 10005 | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | | 20009 | 2005-10-08 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | NULL | NULL | NULL | 10002 | Mouse House | 333 Fromage Lane | Columbus | OH | 43333 | USA | Jerry Mouse | NULL | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 6 rows in set (0.00 sec) # 左外部联结 MariaDB [test]> select orders.*,customers.* from orders left outer join customers on customers.cust_id = orders.cust_id; +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | order_num | order_date | cust_id | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 20005 | 2005-09-01 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20006 | 2005-09-12 00:00:00 | 10003 | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 20007 | 2005-09-30 00:00:00 | 10004 | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 20008 | 2005-10-03 00:00:00 | 10005 | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | | 20009 | 2005-10-08 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 5 rows in set (0.00 sec) # 右外部联结 MariaDB [test]> select orders.*,customers.* from customers right outer join orders on customers.cust_id = orders.cust_id; +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | order_num | order_date | cust_id | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 20005 | 2005-09-01 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20006 | 2005-09-12 00:00:00 | 10003 | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 20007 | 2005-09-30 00:00:00 | 10004 | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 20008 | 2005-10-03 00:00:00 | 10005 | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | | 20009 | 2005-10-08 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 5 rows in set (0.00 sec) # 右外部联结 MariaDB [test]> select orders.*,customers.* from orders right outer join customers on customers.cust_id = orders.cust_id; +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | order_num | order_date | cust_id | cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ | 20005 | 2005-09-01 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | 20006 | 2005-09-12 00:00:00 | 10003 | 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | | 20007 | 2005-09-30 00:00:00 | 10004 | 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | | 20008 | 2005-10-03 00:00:00 | 10005 | 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL | | 20009 | 2005-10-08 00:00:00 | 10001 | 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | | NULL | NULL | NULL | 10002 | Mouse House | 333 Fromage Lane | Columbus | OH | 43333 | USA | Jerry Mouse | NULL | +-----------+---------------------+---------+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+ 6 rows in set (0.00 sec)
聚集函数也可以方便地与其他联结一起使用。请看下面的例子:
检索所有客户及每个客户所下的订单数(包括没有订单的客户)
MariaDB [test]> 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; +----------------+---------+---------+ | cust_name | cust_id | num_ord | +----------------+---------+---------+ | Coyote Inc. | 10001 | 2 | | Mouse House | 10002 | 0 | | Wascals | 10003 | 1 | | Yosemite Place | 10004 | 1 | | E Fudd | 10005 | 1 | +----------------+---------+---------+ 5 rows in set (0.00 sec)
这个例子使用左外部联结来包含所有客户,甚至包含那些没有任何下订单的客户。结果显示也包含了客户 Mouse House ,它有 0 个订单。
组合查询和多个 WHERE 条件 多数情况下,组合相同表的两个查询完成的工作与具有多个 WHERE 子句条件的单条查询完成的工作相同。换句话说,任何具有多个 WHERE 子句的 SELECT 语句都可以作为一个组合查询给出,在以下段落中可以看到这一点。这两种技术在不同的查询中性能也不同。因此,应该试一下这两种技术,以确定对特定的查询哪一种性能更好。
创建组合查询
可用 UNION 操作符来组合数条SQL查询。利用 UNION ,可给出多条SELECT 语句,将它们的结果组合成单个结果集。
1.使用 UNION
UNION 的使用很简单。所需做的只是给出每条 SELECT 语句,在各条语句之间放上关键字 UNION 。
在这个简单的例子中,使用 UNION 可能比使用 WHERE 子句更为复杂。但对于更复杂的过滤条件,或者从多个表(而不是单个表)中检索数据的情形,使用 UNION 可能会使处理更简单。
检索客户信息表中客户名包含Mouse的客户id,以及订单表中,订单号为20005的客户id。
MariaDB [test]> select cust_id from orders where order_num=20005 union select cust_id from customers where cust_name regexp 'Mouse'; +---------+ | cust_id | +---------+ | 10001 | | 10002 | +---------+ 2 rows in set (0.00 sec)
2.UNION 规则
正如所见,并是非常容易使用的。但在进行并时有几条规则需要注意。
UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间用关键字 UNION 分隔(因此,如果组合4条 SELECT 语句,将要使用3个UNION 关键字)。