@FunC
2018-05-15T19:09:13.000000Z
字数 4552
阅读 1777
学习笔记
函数为数据的转换和处理提供了方便,但同时也具有可移植性差的特点(即在不同的DBMS中的支持度,函数名可能不一样)
如果使用函数,应该保证做好代码注释。
大多数SQL实现支持下面四类函数:
1. 文本函数:用于处理字符串
2. 数值函数:对数值数据进行算术运算
3. 日期和时间函数:用于处理日期和时间值
4. 系统函数:返回DBMS相关的信息
下面是一些常用的文本处理函数:
其中SOUNDEX函数是将文本串转换为描述其语音表示的字母数字模式的算法,能对字符串进行发音比较(但不支持中文)。
数值函数在主要的DBMS中实现都比较一致:
一方面,在数据库中,日期和时间采用相应的数据类型储存,DBMS能快速和有效地排序和过滤,并且节省物理存储空间。
另一方面,应用程序一般不使用日期和时间的存储格式,因此日期和时间函数总是用来读取、统计和处理这些值。可惜的是,它们很不一致,可以移植性很差。
-- MYSQL使用YEAR() 函数提取日期
SELECT order_num
FROM Orders
WHERE YEAR(order_date) = 2012;
有时候我们需要将数据汇总后的结果,而不需要实际表数据(如确定表中行数、表中某些行的和、列中的最大值、最小值和平均值等)
为了方便这种类型的检索,SQL给出了5个聚集函数:
聚集函数:
对某些行运行的函数,计算并返回一个值。
AVG()对表中行数进行计数并计算其列值之和,求的该列的平均值。
注意,AVG()只能用于单个列,想获得多个列的平均值必须使用多个AVG()函数。
关于字符串:如果对字符串进行处理,则只计算字符串中的数字
关于NULL值:AVG()函数忽略值为NULL的行
COUNT()函数进行计数。有两种使用方式:
1. 使用COUNT(*)对表中行的数目进行计数(包括NULL值)
2. 使用COUNT(column)对特定列中具有值的行进行计数(忽略NULL值)
MAX() 返回指定列中的最大值。用于文本数据时,返回按该列排序后的最后一行
MIN() 返回指定列中的最小值。用于文本数据时,返回按该列排序后的最前面一行
关于NULL值:均忽略NULL值
SUM()函数用于返回指定列值的和。
SUM()也可以用于合计计算值,如下所示:
SELECT SUM(item_price*quantity) AS total_price
FROM OrderItems
WHERE order_num = 20095;
使用标准的算术操作符,所有聚集函数都可用来执行多个列上的计算。
关于NULL值:忽略值为NULL的行
对于以上5个聚集函数,都能有以下用法:
* 默认行为:对所有行执行计算,即指定ALL参数或不指定参数
* 只包含不同的值,指定DISTINCT参数
SELECT AVG(DISTINCT prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';
注意:DISTINCT不能用于COUNT(*)
SELECT语句可以包含多个聚集函数。
SQL除了能汇总数据,还能将汇总的数据根据一定的逻辑进行分组,这主要通过GROUP BY字句和HAVING字句实现
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id;
对于行的过滤,我们可以使用WHERE。但对于分组的过滤,我们需要使用HAVING(HAVING支持所有WHERE操作符)
HAVING和WHERE的差别:
WHERE在数据分组前进行过滤,HAVING在分组后进行过滤(所以WHERE排除掉的行将不被包含在分组中)
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;
子查询(subquery)即嵌套在其他查询中的查询。常见的使用场景是将某个查询的结果作为另一个查询的检索范围:
数据库中有多张关系表,例如有记录订单的Orders,记录订单具体内容的OrderItems,以及记录顾客信息的Customers。
场景:
需要检索购买了RGAN01的所有顾客的信息
思路:
检索包含RGAN01的订单 -> 检索上述订单中的所有顾客ID -> 根据得到的ID返回所有的顾客信息
于是我们可以利用子查询:
- 适当的缩进便于阅读
SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (SELECT cust_id
FROM Order
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01'));
场景:
检索Customers表中每个顾客的订单总数
思路:
相当于在Customers表中临时加一列,根据每一行的ID,去订单表中COUNT(*)来得到该列数据
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列的数据需要每一行分别生成,所以子查询语句执行了5次(因为结果是5个顾客)。(这不是最有效的方法,用JOIN更佳)
在数据查询的执行中联结(JOIN)表是SQL最强大的功能之一。
将数据分解为多个表能更有效地进行存储和管理,并且伸缩性更好。通过联结,能在一条SELECT语句中关联表
SELECT vend_name, prod_name, prod_price
FROM Vendors, Products - 多个表
WHERE Vendors.vend_id = Products.vend_id;
- 与上面的sql等价
SELECT vend_name, prod_name, prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;
这种基于两个表之间的相等测试的联结称为内联结。
将上一章的子查询改为联结:
SELECT cust_name, cust_contact
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num
AND prod_id = 'RGAN01';
场景:
要检索出与Jim Jones同一公司的所有顾客
思路:
1. 先检索出Jim Jones的公司
2. 然后检索同一公司顾客
因为两步中查询的是同一张表,因此可以使用联结查询(配合别名避免歧义)
SELECT c1.cust_id, c1.cust_name, c1.cust_contact
FROM Customers AS c1, Customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_contact = 'Jim Jones';
在联结时,有时候需要包含没有关联行的那些行(例如注册了还没有过购买记录的顾客),这是可以使用外联结来实现:
SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
其中联结关键字中的LEFT表示列出左边的表的所有行,也可以使用RIGHT OUTER JOIN。
即包含两个表的不关联行(类似于同时使用LEFT和RIGHT),使用 FULL OUTER JOIN 关键字
对于联结查询的结果,我们也可以使用聚集函数来汇总数据。例如我们想检索每个顾客所下的订单数:
SELECT Customers.cust_id,
COUNT(Orders.order_num) AS num_ord
FROM Customers INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id;
主要有两种情况需要使用组合查询:
* 在一个查询中从不同的表返回结构数据
* 对一个表执行多个查询,按一个查询返回数据
大部分情况下,组合查询与具有多个WHERE子句的SELECT语句完成的工作相同
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION - 使用UNION关键字进行组合查询
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';
UNION的默认行为会去除重复的行,如果想保留重复行,可使用UNION ALL关键字(这点WHERE做不到)
注意,对组合查询结果排序时,ORDER BY只能使用一次,并且放在最后一条SELECT语句之后(实际是对组合查询的结果进行排序)