DB2 SQL 与 XQuery 教程,第 2 部分: 基本查询
2009-11-28 00:00:00 来源:WEB开发网开始之前
关于本系列
本教程为您讲解 SQL 的一些基础和高级话题以及 XQuery 的基础知识,并展示如何使用 SQL 查询或 XQuery 语句将常被问起的业务问题表达为数据库查询。开发人员和数据库管理员可以使用本教程来提高他们的数据库查询技能。Academic Initiative 成员可以使用本教程系列作为他们数据库课程的一部分。
本文中的所有例子都是基于 Aroma,这是一个示例数据库,其中包含了在美国各地的商店中出售的咖啡和茶用品的销售数据。每个例子由以下三部分组成:
以日常用语表达的一个业务问题
以 SQL 或 XQuery 表达的一个或多个例子查询
显示从数据库返回的结果的一个表
本指南是为了让读者学习 SQL 语言和 XQuery 而设计的。和学习任何其他技能一样,重要的是一边学习一边实践。本指南给出的表定义和数据为此提供了便利。
对于使用本指南作为学校课程一部分的学生而言,他们应该向老师学习连接到 Aroma 数据库的操作,并了解本指南的设置与您本地设置的不同之处。
本系列是针对于 DB2 Express-C 9 for UNIX®, Linux® and Windows® (曾用名 Viper)而编写的。
关于本教程
本教程通过一系列简单的例子,阐释如何用标准 SQL SELECT 语句检索 IBM DB2 数据库中的数据。
本教程描述如何:
从关系数据库表中检索行
从关系数据库表中检索特定的列
从关系数据库表中检索特定的行
对被检索的数据执行逻辑操作
在搜索条件中使用通配符
连接到数据库
在使用 SQL 查询或处理数据之前,需要连接到一个数据库。CONNECT 语句将一个数据库连接与一个用户名相关联。
如果您使用本指南作为学校课程的一部分,那么可以向老师询问要连接到的数据库的名称。对于本系列,数据库名为 aromadb。
要连接到 aromadb 数据库,可以在 DB2 命令行处理器中输入以下命令:
CONNECT TO aromadb USER userid USING password
注意用老师告诉您的用户 ID 和密码替换 "userid" 和 "password"。如果不需要用户 ID 和密码,那么只需使用以下命令:
CONNECT TO aromadb
下面的消息告诉您已经建立一个成功的连接:
Database Connection Information
Database server = DB2/NT 9.0.0
SQL authorization ID = USERID
Local database alias = AROMADB
建立连接后,就可以开始使用数据库了。
SELECT 语句的六个子句
SQL 语句中有六个可用的子句。这六个子句是 SELECT、FROM、WHERE、GROUP BY、HAVING 和 ORDER BY。这些子句必须按特定的顺序出现。下面简要讨论一下每个子句。当您在本教程后面碰到这些子句时,您将学习到更详细的内容。
1. SELECT | 列名* |
2. FROM | 表或视图 |
3. WHERE | 符合的条件或谓词 |
4. GROUP BY | 行的子集 |
5. HAVING | 一个组中所有行要满足的公共条件 |
6. ORDER BY | 排序方法 |
注: 更确切地说,列名 应称作元素,因为 SELECT 语句既显示表中已有的列也显示 SQL 生成的作为查询结果的列。
例子查询
SELECT perkey, sum(dollars)
FROM aroma.sales
WHERE perkey < 50
GROUP BY perkey
HAVING sum(dollars) > 8000
ORDER BY perkey;
关于该查询
SELECT 子句列出您感兴趣的列。SELECT 将显示您在该子句中指定的列。在 SELECT 中还可以指定其他项,这在后面会解释。在这个例子中,perkey 列和 dollar 列被选中。
FROM 子句指出要从中获取数据的表。您可以列出不止一个表。最多能列出多少个表,这取决于操作系统。在这个例子中,两个列都是从 Sales 表中选择的。
SELECT 和 FROM 都是必需的,其他几个子句则可选,这些子句的作用是过滤或限制、聚合或组合以及控制排序。
WHERE 子句用于指定一个条件。这可以帮助您从结果中过滤掉不想要的数据。WHERE 使返回的结果是表中行的子集。在这个例子中,只有 perkey 值小于 50 的行会被选中。
GROUP BY 子句可用于对数据进行分组,以得到更有意义的结果。在这个例子中,通过指定 GROUP BY perkey,导致不返回所有被选中行的销售额总数,而是按 perkey 划分销售,得到每日的销售总额。
HAVING 为组设置一个条件。在这个例子中,只有销售总额大于 8000 的那些天的记录才会返回。
ORDER BY 对结果行排序。您可以选择按 ASC(升序)或 DESC(降序)排序。缺省情况是 ASC。
SELECT 语句是数据处理语言(DML)中最常用的语句。其他的 DML 语句(UPDATE、INSERT 和 DELETE)以及 SQL 的另外两个组成部分(数据定义语言和控制语言)将在本系列的第 6 部分讨论。
使用 SELECT 语句检索数据
问题
Aroma 数据库中定义了哪些区域、地区和市场?
解决方案
第一步是识别出哪个表包含能回答这个问题的行和列。在第 1 部分中,有一个解释 AROMADB 中各个表的图。在这个图的左下部分,有一个名为 Market 的表,这个表包含了名为 mktkey、 hq_city、hq_state、district 和 region 的一些列。列出这个表中的所有内容,就可以回答上面的问题,而这个任务通过一个 SQL SELECT 语句就能完成。
例子查询
SELECT * FROM aroma.market;
结果
Mktkey | Hq_city | Hq_state | District | Region |
1 | Atlanta | GA | Atlanta | South |
2 | Miami | FL | Atlanta | South |
3 | New Orleans | LA | New Orleans | South |
4 | Houston | TX | New Orleans | South |
5 | New York | NY | New York | North |
6 | Philadelphia | PA | New York | North |
7 | Boston | MA | Boston | North |
8 | Hartford | CT | Boston | North |
9 | Chicago | IL | Chicago | Central |
10 | Detroit | MI | Chicago | Central |
11 | Minneapolis | MN | Minneapolis | Central |
12 | Milwaukee | WI | Minneapolis | Central |
14 | San Jose | CA | San Francisco | West |
15 | San Francisco | CA | San Francisco | West |
16 | Oakland | CA | San Francisco | West |
17 | Los Angeles | CA | Los Angeles | West |
19 | Phoenix | AZ | Los Angeles | West |
检索数据:SELECT 语句
使用 SELECT 语句可以从数据库表中检索列和行数据;可以对数据执行算术运算;可以对数据进行分组、排序或者同时分组和排序。在大多数情况下,一个 SELECT 语句包含一个以 SELECT 关键字开头的简单查询表达式,后面跟上一个或多个子句或子句的子句。
最基本的 SELECT 语句包含两个关键字,即 SELECT 和 FROM:
SELECT column name(s)
FROM table name(s)
column name(s) | 以逗号隔开的列名或 SQL 表达式。也可以用星号(*)列出给出的表中的所有列。 |
table name(s) | 可以是一组表或一个 SELECT 语句。表名之间以逗号隔开。被引用的表必须包含 SELECT 关键字后面引用到的列。在这个例子中,FROM 语句引用 AROMA.MARKET 表。在第 3 部分,表名及模式 中将对这个命名惯例作详细的讨论。在这个例子中,FROM 子句引用全限定的表名。第一部分是模式,第二部分是表名。模式对于将相似的表或其他 DB2 对象组织在一起很有用。在 AROMADB 数据库中,所有表都以 AROMA 作为模式。 |
等效的 select 语句
SELECT mktkey, hq_city, hq_state, district, region FROM aroma.market
上面的查询返回的结果与 SELECT * FROM aroma.market 是一样的,但是,这个查询没有使用星号(*),而是一一指定列名。
要点:SELECT 和 FROM(以及所有以大写形式显示的词)都是保留的 SQL 关键字。这些词必须严格按照 SQL 标准的规定来使用。在本文中,为了突出关键字,我们使用大写形式来显示关键字。SQL 不区分大小写,所以关键字既可以写成大写形式,也可以写成小写形式。 |
使用中的注意事项
在本指南中,每个例子后面的分号并不是 SQL 语法强制要求的。按照惯例,SQL 语言忽略额外的空格、制表符和行尾指示符。分号是语句末标记符,如果只是执行一条语句,那么这个分号不是必需的。如果是创建一个包含一系列 SQL 语句的脚本,那么分号可用于界定每条语句的结束。您可以根据用于输入查询的交互式 SQL 工具,来决定需不需要指定这样的一个标记符。当使用命令行处理器来执行多条 SQL 语句时,必须使用分号来表明每条语句的结束。
使用 SELECT 列表检索特定的列
问题
Aroma 数据库中定义了哪些地区和区域?
例子查询
SELECT district, region
FROM aroma.market;
结果
District | Region |
Atlanta | South |
Atlanta | South |
New Orleans | South |
New Orleans | South |
New York | North |
New York | North |
Boston | North |
Boston | North |
Chicago | Central |
Chicago | Central |
Minneapolis | Central |
Minneapolis | Central |
San Francisco | West |
San Francisco | West |
San Francisco | West |
Los Angeles | West |
Los Angeles | West |
检索特定的列
通过在 SELECT 语句的 SELECT 列表中指定列名,可以从任何表中检索一组特定的列。返回的列的顺序与 SELECT 列表中指定列的顺序一致。
关于该查询
这个例子查询请求 Market 表中的地区及其对应的区域的一个列表。
使用中的注意事项
虽然 SELECT 列表中的列名必须在 FROM 子句引用的表中有定义,但是 SELECT 列表中也可以出现其他表达式。本系列后面会讨论关于那样的表达式的一些例子。
如果 SELECT 列表没有包括表中所有的列,那么一个查询可能返回重复的行,前面的例子查询也展示了这一点。不过,可以通过使用 DISTINCT 关键字消除重复的行。例如,下面的查询只返回 Market 表中不同的地区和区域名称。
SELECT DISTINCT district, region
FROM aroma.market;
District | Region |
Chicago | Central |
Minneapolis | Central |
Boston | North |
New York | North |
Atlanta | South |
New Orleans | South |
Los Angeles | West |
San Francisco | West |
使用 WHERE 子句检索特定的行
问题
哪些产品是不带包装出售的?
例子查询
SELECT prod_name, pkg_type
FROM aroma.product
WHERE pkg_type = 'No pkg';
结果
Prod_Name | Pkg_Type |
Veracruzano | No pkg |
Xalapa Lapa | No pkg |
Colombiano | No pkg |
Expresso XO | No pkg |
La Antigua | No pkg |
Lotta Latte | No pkg |
Cafe Au Lait | No pkg |
NA Lite | No pkg |
Aroma Roma | No pkg |
Demitasse Ms | No pkg |
Darjeeling Number 1 | No pkg |
Darjeeling Special | No pkg |
Assam Grade A | No pkg |
Assam Gold Blend | No pkg |
Earl Grey | No pkg |
English Breakfast | No pkg |
Irish Breakfast | No pkg |
Special Tips | No pkg |
Gold Tips | No pkg |
Breakfast Blend | No pkg |
Ruby's Allspice | No pkg |
Coffee Mug | No pkg |
Travel Mug | No pkg |
Aroma t-shirt | No pkg |
Aroma baseball cap | No pkg |
检索特定的行:WHERE 子句
通过在查询中包括一组逻辑条件,可以从表中检索一组特定的行。逻辑条件是在 WHERE 子句中声明的。如果某个行满足该条件,那么查询就返回该行;如果某个行不满足条件,那么查询就放弃该行。逻辑条件也称搜索条件、谓词、约束或限定。
WHERE 子句
SELECT column name(s) FROM table name(s) [WHERE search_condition];
search_condition | 这个条件的值为 true 或 false |
方括号([ ])表明 WHERE 子句是可选的。
关于该查询
这个例子查询检索和显示没有预先包装或打包的产品的名称。IBM DB2 9 对于 Product 表中的每一行计算以下条件,然后只返回满足条件的那些行:
pkg_type = 'No pkg'
使用中的注意事项
字符文字是以单引号括起来的一个字符串。为表示字符文字中的单引号,可以使用两个单引号('')。例如: 'Scarlet O''Hara'
字符文字必须严格按照存储在数据库中的样子表达,不能混淆大小写。例如,下面的条件:
class_type = 'Bulk_beans'
将为 false,如果被引用的列包含的是以下字符串的话:
'BULK_beans'
WHERE 子句中不允许使用集合函数。要了解关于集合函数的更多信息,请参阅第 3 部分,使用 ORDER BY 子句。
使用 AND、NOT 和 OR 连接词创建复杂条件
问题
哪些城市和地区位于南部或西部区域?
例子查询
SELECT hq_city, district, region
FROM aroma.market
WHERE region = 'South' OR region = 'West';
结果
Hq_city | District | Region |
Atlanta | Atlanta | South |
Miami | Atlanta | South |
New Orleans | New Orleans | South |
Houston | New Orleans | South |
San Jose | San Francisco | West |
San Francisco | San Francisco | West |
Oakland | San Francisco | West |
Los Angeles | Los Angeles | West |
Phoenix | Los Angeles | West |
指定复合条件:AND、OR、NOT 和括号
为了提高对行的选择的精确性,可以将搜索条件结合使用,还可以强制规定计算顺序。一个搜索条件指定一个条件,一个给定行对于这个条件的回答为 "true"、"false" 或 "unknown"。搜索条件的结果是通过将指定逻辑操作符(AND、OR、NOT)应用于每个指定谓词的结果而得到的。如果没有指定逻辑操作符,那么搜索条件的结果就是指定谓词的结果。AND 和 OR 的定义如下表所示,其中 P 和 Q 是任意谓词:
AND 和 OR 的真值表
P | Q | P AND Q | P OR Q |
True | True | True | True |
True | False | False | True |
True | Unknown | Unknown | True |
False | True | False | True |
False | False | False | False |
False | Unknown | False | Unknown |
Unknown | True | Unknown | True |
Unknown | False | False | Unknown |
Unknown | Unknown | Unknown | Unknown |
NOT(true) 为 false,NOT(false) 为 true,NOT(unknown) 为 unknown。
括号中的搜索条件首先被计算。如果没有用括号指定计算顺序,那么 NOT 优先于 AND, AND 优先于 OR。这里没有定义相同优先级上的操作符的计算顺序,以优化搜索条件。
在 WHERE 子句中使用 AND、OR 和括号
问题
在洛杉矶或圣何塞有哪些大型的或小型的 Aroma Coffee and Tea Company 店?
例子查询
SELECT store_type, store_name, city
FROM aroma.store
WHERE (store_type = 'Large' OR store_type = 'Small')
AND (city = 'Los Angeles' OR city = 'San Jose');
结果
Store_Type | Store_Name | City |
Large | San Jose Roasting Company | San Jose |
Large | Beaches Brew | Los Angeles |
Small | Instant Coffee | San Jose |
指定复杂搜索条件
搜索条件,尤其是那些为决策支持分析编写的查询中的搜索条件,可能比较复杂。复杂的条件是由简单的条件加上 AND、OR 和 NOT 等连接词构造而成的,有时候这种条件可能难于理解。幸运的是,SQL 是格式自由的,所以可以借助制表符、空格和换行符来显示这些条件的逻辑结构,以明确逻辑关系。
关于该查询
这个例子查询检索和显示位于洛杉矶或圣何塞的大型或小型 Aroma Coffee and Tea Company 店。
这个查询中的括号是必需的,因为连接词 AND 比 OR 具有更高的优先级。如果去掉括号,那么查询将返回不同的结果。
例子查询(没有括号)
SELECT store_type, store_name, city
FROM aroma.store
WHERE store_type = 'Large' OR store_type = 'Small'
AND city = 'Los Angeles' OR city = 'San Jose';
结果
Store_Type | Store_Name | City |
Large | San Jose Roasting Company | San Jose |
Large | Beaches Brew | Los Angeles |
Small | Instant Coffee | San Jose |
Large | Miami Espresso | Miami |
Large | Olympic Coffee Company | Atlanta |
使用中的注意事项
查询将检索和显示没有被它的搜索条件显式排除掉的所有数据,如果查询只有比较笼统的搜索条件,那么就会返回大量的行。
一旦不确定服务器将如何计算一个复合条件,那么可以显式地用括号来确立计算顺序。
使用大于(>)和小于或等于(<=)操作符
问题
Mktkey 值大于 4 并且小于或等于 12 的城市和地区有哪些?
例子查询
SELECT mktkey, hq_city, hq_state, district
FROM aroma.market
WHERE mktkey > 4
AND mktkey <= 12;
结果
Mktkey | Hq_City | Hq_State | District |
5 | New York | NY | New York |
6 | Philadelphia | PA | New York |
7 | Boston | MA | Boston |
8 | Hartford | CT | Boston |
9 | Chicago | IL | Chicago |
10 | Detroit | MI | Chicago |
11 | Minneapolis | MN | Minneapolis |
12 | Milwaukee | WI | Minneapolis |
使用比较操作符
条件的值为 true 或 false,它们可以用比较操作符或比较谓词来表达。SQL 包含以下比较操作符:
操作符 | 名称 |
= | 等于 |
< | 小于 |
> | 大于 |
<> | 不等于 |
>= | 大于或等于 |
<= | 小于或等于 |
关于该查询
这个例子查询检索和显示 Mktkey 大于 4 但小于或等于 12 的那些城市和地区。
Mktkey 列包含整数值,而整数值是可以与其他数值进行比较的。但是,如果将一个整数与一个字符进行比较,那么服务器将返回一条错误消息:
SELECT mktkey, hq_city, hq_state, district
FROM aroma.market
WHERE mktkey > '4';
[IBM][CLI Driver][DB2/LINUX] SQL0401N The data types of the operands
for the operation ">" are not compatible. SQLSTATE=42818
您可以通过 DB2 Information Center 获得对错误消息的解释,并发现可以采取的更正措施。本系列的第 1 部分对 DB2 Information Center 进行了介绍。
使用中的注意事项
条件只能比较具有可比较数据类型的值。如果试图比较不同的数据类型,那么服务器要么返回错误消息,要么返回不正确的结果。比较操作符可用于将一个字符串与另一个字符串进行比较,下面的条件对此做了演示,这个条件是有效的:
(city > 'L')
使用 IN 比较谓词
问题
在芝加哥、纽约和新奥尔良有哪些城市?
例子查询
SELECT hq_city, hq_state, district
FROM aroma.market
WHERE district IN
('Chicago', 'New York', 'New Orleans');
结果
Hq_City | Hq_State | District |
New Orleans | LA | New Orleans |
Houston | TX | New Orleans |
New York | NY | New York |
Philadelphia | PA | New York |
Chicago | IL | Chicago |
Detroit | MI | Chicago |
使用比较谓词
用下面的 SQL 比较谓词可以表达简单的条件:
谓词 |
BETWEEN expression1 AND expression2 |
LIKE pattern |
IN (list) |
IS NULL |
IS NOT NULL |
ALL |
SOME 或 ANY |
EXISTS |
本系列的第 5 部分有关于 ALL、SOME 或 ANY 以及 EXISTS 谓词的例子。
关于该查询
这个例子查询列出芝加哥、纽约和新奥尔良的所有城市。这个查询可以使用等于比较操作符(=)和一组 OR 条件来编写:
WHERE district = 'Chicago'
OR district = 'New York'
OR district = 'New Orleans'
使用中的注意事项
尽量将逻辑条件编写得简单、易于理解并且容易维护。总是用充足的空白使复合条件的逻辑结构清晰明了,用缩进的方式定义逻辑块,并且用括号保证计算的优先顺序。
使用百分号(%)通配符
问题
以 Min 开头的地区中有哪些城市?
例子查询
SELECT district, hq_city
FROM aroma.market
WHERE district LIKE 'Min%';
结果
District | Hq_City |
Minneapolis | Minneapolis |
Minneapolis | Milwaukee |
使用通配符
前面的查询表达了与完整的字符串相匹配的条件。而通过 LIKE 谓词和两个通配符,即百分号(%)和下划线(_),还可以表达与一个字符串的一部分(一个子串)相匹配的条件。
百分号(%)通配符匹配任意字符串。例如:
like 'TOT%' 对于以 'TOT' 开头的任意字符串都为 true。
like '%ZERO%' 对于包含 'ZERO' 的任意字符串都为 true。
like '%FRESH' 对于以 'FRESH' 结束并且不包含结尾空白的任意字符串都为 true。当应用 LIKE 约束时,结尾空白不容忽视。
百分号(%)还可以用于搜索空字符串——即零(0)字符串。
下划线通配符(_)匹配一个固定位置上的任意字符。例如:
like '_EE_' 对于包含 4 个字符,且中间两个字符是 'EE' 的任意字符串为 true。
like '%LE_N%' 对于包含 'LE_N' 这种模式的任意字符串为 true。字符串 'CLEAN'、'KLEEN' 和 'VERY KLEEN' 都与该模式相匹配。
关于该查询
这个例子查询检索所有以 'Min' 开头的地区的名称,并列出这些地区中的城市。通配符百分号(%)允许 'Min' 中的 'n' 之后出现任意字符组合,但是在 'n' 之前的字符则必须完全与指定的字符模式相匹配。
使用中的注意事项
对于 LIKE 条件,当它的模式与一个列中的一个子串匹配时,它的值便为 true。如果模式中没有包含通配符,那么这个模式必须与列中的字符串完全匹配。
例如,下面的条件只有当列中仅包含字符串 APRIL 而没有其他字符时才为 true:
month LIKE 'APRIL'
换句话说,这个条件相当于:
month = 'APRIL'
LIKE 谓词只能用在包含字符串的列上。
使用 AS 子句为列命名
问题
以 Min 开头的地区中有哪些城市?为 hq_city 列起一个更有意义的名称。
例子查询
SELECT district, hq_city AS City
FROM aroma.market
WHERE district LIKE 'Min%';
结果
District | City |
Minneapolis | Minneapolis |
Minneapolis | Milwaukee |
命名表达式:AS
AS 子句是一种可选的子句,通过它可以为表达式起一个有意义的名称,而这个名称则反过来引用之前的表达式。当使用 AS 子句时,关于可使用的名称有一些规则。通常,有效的名称必须以字母开头,长度不超过 128 个字符,没有空格,并且不是 SQL 关键字。SQL 关键字有 SELECT、FROM、WHERE 等。
例如,下面的 AS 子句为 hq_city 列指定别名 City:
hq_city AS City
也可以不使用关键字 AS 来指定别名,但是这样看起来不够明显:
hq_city City
您将注意到,虽然表达式中列标题是以首字母大写形式出现的,但是最终将显示为全大写形式。
关于该查询
这个例子查询返回的结果与本章前一个查询返回的结果一致。但是,这个例子指定了列的别名,用于为聚合的结果创建标题。
要点:如果列别名所引用的列中包含的值是一个集合函数的结果,那么它不能出现在 WHERE 子句中,但是它可以出现在 HAVING 子句中。要了解关于 HAVING 子句的更多信息,请参阅本系列的第 4 部分。 |
结束语
SELECT 语句
SELECT column name(s)
FROM table name(s)
[WHERE search_condition]
[GROUP BY group_list]
[HAVING search_condition]
[ORDER BY order_list];
搜索条件
( ) | 括号(强行确立计算顺序) |
NOT | 非 |
AND | 与 |
OR | 或 |
比较操作符
= | 等于 |
< | 小于 |
> | 大于 |
<> | 不等于 |
>= | 大于或等于 |
<= | 小于或等于 |
比较谓词
BETWEEN | expression1 AND expression2 |
LIKE | pattern |
IN | (list) |
IS | NULL |
IS | NOT NULL |
本教程讨论了如何用 SELECT 语句来表达很多常被问起的业务问题,以及如何从关系表中检索数据和对数据进行分组和排序。
本教程中讨论的大部分问题都很容易用标准的 SELECT 语句来表达,对于用户和 SQL 都没有多大的挑战。本系列接下来的教程将解决更有难度的问题,这些问题涉及到顺序处理、对聚合的值的比较,以及更复杂的连接规范或冗长的 SELECT 语句。
在继续阅读下一部分之前,您应该从 DB2 Information Center 中阅读关于 SELECT 语句的全部在线文档。这将有助于让您熟悉帮助文档的格式,并回顾刚才所学到的内容。
本文示例源代码或素材下载
更多精彩
赞助商链接