8、使用函数处理数据 8.1 函数 函数一般是在数据上执行的,为数据的转换和处理提供了方便 函数带来的问题: 表8-1 DBMS函数的差异 函 数 语 法 提取字符串的组成 Access 使用MID() ; DB2 、Oracle 、PostgreSQL 和SQLite 使用 部分 SUBSTR();MySQL和SQL Server使用SUBSTRING() 数据类型转换 Access和Oracle使用多个函数,每种类型的转换有一个函数;DB2 和PostgreSQL使用CAST();MariaDB、MySQL和SQL Server使用 CONVERT() 取当前日期 Access使用NOW() ; DB2 和PostgreSQL 使用CURRENT_DATE ; MariaDB和MySQL使用CURDATE();Oracle使用SYSDATE;SQL Server使用GETDATE();SQLite使用DATE() 可以看到与SQL语句不一样,SQL函数是不可移植的。这就意味着特定SQL实现编写的代码 在其他实现中可能不正常。 可移植(portable) 所编写的代码可以在多个系统上运行! 提示:是否应该使用函数? 决定权在你,如果你决定使用函数,应该保证做好代码注释,以便以后你(或其他人)能确切地 知道你所编写的SQL代码的含义。 8.2 使用函数 大多数SQL支持以下类型的函数 1)处理文本字符串:(删除或填充值,转换值为大写或小写)文本函数 2)用于在数值数据上进行算术操作(如返回绝对值,进行代数运算)的数值函数 3)用于处理日期和时间并从这些值中提取特定成分(如返回两个日期之差,检查日期有效性)的日期和时间函数 4)返回DBMS正使用的特殊信息(如返回用户登录信息)的系统函数 8.2.1 文本处理函数 前面学过的TRIM()函数擦去空格 这次使用的是UPPER()函数 例子: SELECT vend_name,UPPER(vend_name) AS vend_name_upcase FROM Vendors ORDER BY vend_name; 输出: vend_name vend_name_upcase --------------------------- ---------------------------- Bear Emporium BEAR EMPORIUM Bears R Us BEARS R US Doll House Inc. DOLL HOUSE INC. Fun and Games FUN AND GAMES Furball Inc. FURBALL INC. Jouets et ours JOUETS ET OURS 可以看出,UPPER()将文本转换为大写,因此本例子中每个供应商出现两次 第一次为Vendors表中存储的值,第二次作为列vend_name_upcase转换为大写。 以下为常用的文本处理函数 函数 说明 LEFT()(或使用子字符串函数) 返回字符串左边的自字符 LENGTH()(也使用DATALENGTH()或LENN()) 返回字符串的长度 LOWER()(Access使用LCASE()) 将字符串转换为小写 LTRIM() 去掉字符串左边的空格 RIGHT(或使用字符串函数) 返回字符串右边的字符 RTRIM() 去掉字符串右边的空格 SOUNDEX() 返回字符串的SOUNDEX值 UPPER()(Access使用UCASE()) 将字符串转换为大写 SOUNDEX是一个将任何文本串转换为描述其语音表示的字母数字模式的算法,SOUNDEX考虑了 类似的发音字符和音节,是的能对字符串进行发音比较而不是字母比较。 Access和PostgreSQL不支持SOUNDEX()因此一下的例子不适用这些DBMS 例子:。Customers 表中有一个顾客 Kids Place,其联系名为Michelle Green。但如果这是错误的输入, 此联系名实际上应该是Michael Green,该怎么办呢?显然,按正确的 联系名搜索不会返回数据,现在试一下使用SOUNDEX()函数进行搜索,它匹配所有发音类似于 Michael Green 的联系名: SELECT cust_name,cust_contact FROM Customers WHERE SOUNDEX(cust_contact) = SUNDEX(‘Michael Green‘); 输出: cust_name cust_contact ------------------------------------------- kids Place Michelle Green 8.2.2 日期和时间处理函数 应用程序一般不适用日期和时间的存储格式,因此日期和时间函数总是用来读取、统计 和处理这些值。由于这个原因,日期和时间函数在SQL中具有重要的作用。遗憾的是,它们 很不一致,可移植性最差。 例子:检索2012年的所有订单 SELECT * FROM Orders WHERE DATEPART(yy,order_date)=2012; 在Access中使用如下版本 SELECT order_num FROM Orders WHERE DATEPART(‘yyyy‘,order_date) =2012; 下面是使用名为DATE_PART()的类似函数的PostgreSQL版本 SELECT order_num FROM Orders WHERE DATE_PART(‘year‘,order_date) =2012; Oracle没有DATEPART()函数,不过有几个可用来完成相同检索的日期处理函数 SELECT order_num FROM Orders WHERE to_number(to_char(order_date,‘YYYY‘))=2012; 这个例子中,to_char()函数用来提取日期的成分,to_number()用来将提取出的成分转换为数值 以便能与2012进行比较 完成相同工作的另一个方法是使用BETWEEN操作符 SELECT order_num FROM Orders WHERE order_date BETWEEN to_date(‘01-01-2012‘) AND to_date(‘12-31-2012‘); 值得注意的是相同的代码在SQL Sever 中不起作用,因为它不支持to_date()函数 但是,如果用CONVERT()替换to_date()当然可以使用这种类型的语句 MySQl 和MAriaDB具有个各种日期处理函数,但没有DATEPART(). MySQL和MariaDB用户可使用名为YEAR()的函数从日期中提取年份 输入: SELECT order_num FROM Orders WHERE YEAR(order_date) =2012; 8.2.3 数值处理函数 数值处理函数仅处理数值数据。这些函数一般主要用于代数、三角函数或几何运算 因此不像字符串货日期——时间处理函数使用的那么频繁 具有讽刺意味的是,在主要的DBMS的函数中,数值函数是最一致,最同意的函数 常用数值处理函数 函数 说明 ABS() 返回一个数的绝对值 COS() 返回一个角度的余弦 EXP() 返回一个数的指数值 PI() 返回圆周率 SIN() 返回一个角度的正弦 SQRT() 返回一个数的平方根 TAN() 返回一个角度的正切 9、汇总数据 9.1 聚集函数 这种类型的检索例子有: #确定表中的行数(或者满足某个条件) #获得表中某些行的和: #找出表列(或所有行或特定的行)最大值、最小值、平均值 聚集函数(aggregate function) 对某些行运行的函数、计算并返回一个值 SQL聚集函数在各种主要SQL实现中得到了相当一致的支持 SQL 聚集函数 函数 说明 AVG() 返回某列的平均值 COUNT() 返回某列的行数 MAX() 返回某列的最大值 MIN() 返回某列的最小值 SUN() 返回某列值之和 9.1.1 AVG()函数 AVG()通过对表中行数计数并计算其列值之和,求得该列的平均值。 可返回所有列的平均值,也可以用来返回特定列或行的平均值 输入: SELECT AVG(prod_price) AS avg_price FROM Products; 输出 avg_price -------------------------------------------------- 6.82333333 注意:只用于单个列 AVG()只能用来确定特定数值列的平均值,而且列名必须作为 函数参数给出。为了获得多个列的平均值,必须使用多个AVG() AVVG()函数忽略列值为NULL的行! 9.1.2 COUNT()函数 COUNT()函数进行计数。可利用COUNT()确定表中的数目或符合规定条件的行数目 COUNT()函数有两种使用方式: (1) 使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(null)还是 非空值。 (2) 使用COUNT(column)对特定列中具有值得行进行计数,忽略null值。 代码: 输入: --返回Customers表中顾客的总数 SELECT COUNT(*) AS num_cust FROM Customers; ------------------------------- 输出: num_cust ------- 5 说明:NULL值 如果指定列名,则COUNT()函数会忽略指定列的值为空的行,但如果COUNT()函数中 用的是(*),则不忽略 9.1.3 MAX()函数 MAX()返回指定列中的最大值。MAX()要求指定列名, 代码 输入: SELECT MAX(prod_price) AS max_price FROM Products; 输出: max_price --------- 11.9900 提示:对非数值数据使用MAX() 虽然 MAX() 一般用来找出最大的数值或者日期值,但许多(并非所有)DBMS 允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。在用于文本数据 时候,MAX()返回按该列排序后的最后一行。 说明:NULL 值 MAX()函数忽略值为NULL的行 9.1.4 MIN()函数 MIN() 函数与MAX()功能相反,它返回指定列的最小值。与MAX()一样,MIN()要求指定列名 例子: SELECT MIN(prod_price) AS min_price FROM Products; 输出: min_price ----------- 3.4900 提示:对非数值数据使用MIN() 如MAX()函数一样,在用于文本数据时,MIN()返回该列排序后最前面的行。 说明:NULL值 MIN()函数忽略列值为NULL的行 9.1.5 SUM()函数 SUM() 用来返回指定列值得和(总计) 输入 SELECT SUM(quantity) AS items_ordered FROM OrderItems WHERE order_num = 20005; 输出 items_ordered ---------- 200 分析: 函数SUM(quantity)返回订单中所有物品数量之和,WHERE 子句保证只 统计某个物品订单中的物品。 SUM()也可以用来合计计算值。在下面的例子中,合计每项物品的 item_price*quantity,得出总的订单金额: 输入: SELECT SUM(item_price*quantity) AS total_price FROM OrderItems WHERE order_num = 20005; 输出: total_price ---------- 1648.0000 分析: 函数SUM(item_price*quantity)返回订单中所有物品价钱之和, WHERE 子句同样保证只统计某个物品订单中的物品。 提示: 在多个列上进行计算 如本例所示,利用标准的算术操作符,所有聚集函数都可用来执行多个列上的计算。 说明: NULL 值 SUM()函数忽略列值为NULL 的行 9.2聚集不同的值 以上5个聚集函数都可以如下使用: 对所有执行计算,指定ALL参数或不指定参数(因为ALL是默认行为。) 只包含不同的值,指定DISTINCT参数 提示:ALL为默认 ALL参数不需要指定,因为它是默认行为,如果不指定DISTINCT则假定为ALL。 说明:不要在Access中使用 Microsoft Access在聚集函数中不支持DISTINCT,因此下面的例子不适合于 Access,要在Access得到类似的结果,需要使用子查询把DISTTINCT数据返回到外部 SELECT COUNT(*)语句 输入: SELECT AVG(DISTINCT prod_price) AS avg_price FROM Products WHERE vend_id = ‘DLL01‘; 输出: avg_price ----------- 4.2400 注意: DISTINCT不能用于COUNT(*),DISTINCT必须使用列名,不能用于计算或表达式 将DISTINCT用于MIN()和MAX()实际上是没有价值的,一个列中的极值不论是否考虑 不同值其结果都是相同的。 9.3组合聚集函数 SELECT 语句可根据需要包含多个聚集函数 输入: SELECT COUNT(*) AS num_items, MIN(prod_price) AS price_min, MAX(prod_price) AS price_max, AVG(prod_price) AS price_avg FROM Products; 输出: num_items price_min price_max price_avg ---------- --------------- --------------- --------- 9 3.4900 11.9900 6.823333 注意:取别名 在指定别名以包含某个聚集函数的结果时,不应该使用表中实际的列 名。虽然这样做也算合法,但许多SQL 实现不支持,可能会产生模糊 的错误消息。 9.4小结 聚集函数用来汇总数据。SQL 支持5个聚集函数, 10、分组数据 为便于汇总表内容的子集,需用到SELECT 的两个子句GROUP BY 和 HAVING 10.1数据分组 比如下面的例子返回供应商DLL01 提供的产品数目: 输入: SELECT COUNT(*) AS num_prods FROM Products WHERE vend_id = ‘DLL01‘; 输出: num_prods ----------- 4 10.2创建分组 分组是使用SELECT 语句的GROUP BY 子句建立的。 例子: 输入: SELECT vend_id, COUNT(*) AS num_prods FROM Products GROUP BY vend_id; 输出: vend_id num_prods ------- --------- BRS01 3 DLL01 4 FNG01 2 分析: 因为使用了GROUP BY,就不必指定要计算和估值的每个组了。系统会自 动完成。GROUP BY 子句指示DBMS 分组数据,然后对每个组而不是整 个结果集进行聚集。 注意: GROUP BY 子句可以包含任意数目的列,因而可以对分组进行嵌套, 更细致地进行数据分组。 如果在GROUP BY 子句中嵌套了分组,数据将在最后指定的分组上进 行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以 不能从个别的列取回数据)。 GROUP BY 子句中列出的每一列都必须是检索列或有效的表达式(但 不能是聚集函数)。如果在SELECT 中使用表达式,则必须在GROUP BY 子句中指定相同的表达式。不能使用别名。 大多数SQL 实现不允许GROUP BY 列带有长度可变的数据类型(如文 本或备注型字段)。 除聚集计算语句外,SELECT 语句中的每一列都必须在GROUP BY 子句 中给出。 如果分组列中包含具有NULL 值的行,则NULL 将作为一个分组返回。 如果列中有多行NULL 值,它们将分为一组。 GROUP BY 子句必须出现在WHERE 子句之后,ORDER BY 子句之前。 提示:ALL 子句 Microsoft SQL Server 等有些SQL 实现在GROUP BY 中支持可选的ALL 子句。这个子句可用来返回所有分组,即使是没有匹配行的分组也返 回(在此情况下,聚集将返回NULL)。具体的DBMS 是否支持ALL, 请参阅相应的文档。 10.3过滤分组 除了用GROUP BY 分组数据外,SQL还允许过滤分组,WHERE过滤指定的是行而不是分组 事实上,WHEER没有分组概念。SQL为此提供了HAVING子句。HAVING非常类似于WHERE 事实上目前为止所学过的所有类型的WHERE子句都可以用HAVING替代 差别就是:WHERE过滤行,HAVING过滤分组。 例子: 输入: SELECT cust_id, COUNT(*) AS orders FROM Orders GROUP BY cust_id HAVING COUNT(*) >= 2; 输出: cust_id orders ---------- ----------- 1000000001 2 分析: 这条SELECT 语句的前三行类似于上面的语句。最后一行增加了HAVING 子句,它过滤COUNT(*) >= 2(两个以上订单)的那些分组。 可以看到,WHERE 子句在这里不起作用,因为过滤是基于分组聚集值, 而不是特定行的值。即是:WHERE在数据分组前进行过滤,HAVING在数据分组后 进行过滤。 例子: 输入: SELECT vend_id, COUNT(*) AS num_prods FROM Products WHERE prod_price >= 4 GROUP BY vend_id HAVING COUNT(*) >= 2; 输出: vend_id num_prods ------- ----------- BRS01 3 FNG01 2 分析: 。WHERE 子句过滤所有prod_price 至少为4 的行,然后按vend_id 分组数据,HAVING 子句过滤计数为2 或2 以上的分组。 10.4分组和排序 GROUP BY 和 ORDER BY 经常完成相同的工作,但他们非常不同 差别: ORDER BY GROUP BY 对产生的输出排序 对行分组,但输出可能不是分组的顺序 任意列都可以使用(甚至非 只可能使用选择列或表达式列,而且必须使用每个选择列 选择的列也可以使用) 表达式 不一定需要 如果与聚集函数一起使用列(或表达式),则必须使用 注意: 用GROUP BY 分组的数据确实是以分组顺序输出的。但并不总是这样,这不是SQL 规范 所要求的 例子: 输入: SELECT order_num, COUNT(*) AS items FROM OrderItems GROUP BY order_num HAVING COUNT(*) >= 3; 输出: order_num items --------- ----- 20006 3 20007 5 20008 5 20009 3 需按照订购物品的数目排序输出,需要添加ORDER BY 子句 输入: SELECT order_num, COUNT(*) AS items FROM OrderItems GROUP BY order_num HAVING COUNT(*) >= 3 ORDER BY items, order_num; 输出▼ order_num items --------- ----- 20006 3 20009 3 20007 5 20008 5 10.5 SELECT子句顺序 子 句 说 明 是否必须使用 SELECT 要返回的列或表达式 是 FROM 从中检索数据的表 仅在从表选择数据时使用 WHERE 行级过滤 否 GROUP BY 分组说明 仅在按组计算聚集时使用 HAVING 组级过滤 否 ORDER BY 输出排序顺序 否 10.6小结 如何使用GROUP BY子句对多组数据进行汇总计算,返回每个组的结果。 HAVING子句过滤特定的组,ORDER BY 和 GROUP BY之间以及WHERE和 HAVING之间的差异。 11、使用子查询 11.1子查询 本案例当中使用的数据库表都是关系表,SQL 还允许创建子查询(subquery),即嵌套在其他查询中的查询 查询(query)
原文地址:https://www.cnblogs.com/huaweiming/p/9645891.html
时间: 2024-10-10 17:54:44