--SELECT vend_name FROM Vendors ORDER BY vend_name;
--SELECT vend_name
--FROM Vendors
--WHERE vend_name = 'Bear Emporium' OR vend_name = 'Furball Inc.';
--SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')'
--FROM Vendors ORDER BY vend_name;
--SELECT vend_name + ' (' + vend_country + ')'
--FROM Vendors ORDER BY vend_name;
--许多数据库(不是所有)保存填充为列宽的文本值。
--为正确返回格式化的数据,必须去掉这些空格。
--RTRIM函数去掉值右边的所有空格。
--TRIM函数 大多数DBMS支持RTRIM()(去掉串的右边空格),
--LTRIM()(去掉串的左边空格),TRIM()(去掉串左右两边的空格)。
--alias 别名 关键字 AS
--SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')' AS vend_title
--FROM Vendors ORDER BY vend_name;
--别名可以是一个单词或者一个字符串。如果使后者,串应该括在引号中。
--SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')' AS 'vend_title'
--FROM Vendors ORDER BY vend_name; --这样也可以 同上
--SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')' AS 'vend title'
--FROM Vendors ORDER BY vend_name; --可以
--SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')' AS vend title
--FROM Vendors ORDER BY vend_name; --error 没有引号
--使用AS关键字的时候,最好都加上引号。
--SELECT prod_id, quantity, item_price FROM OrderItems WHERE order_num = 20008;
--quantity 数量
--SELECT prod_id, quantity, item_price, quantity * item_price AS expanded_price
--FROM OrderItems WHERE order_num = 20008;
-- +-*/ 加减乘除
--函数 function
--SELECT vend_name, UPPER(vend_name) AS vend_name_upcase
--FROM Vendors ORDER BY vend_name; --UPPER 转换为大写
--函数列表(常用的文本处理函数)
--LEFT()(或使用子字符串函数) 返回串左边的字符
--LENGTH()(也使用DATELENGTH()或LEN()) 返回串的长度
--LOWER()(Access使用LCASE()) 将串转换为小写
--LTRIM() 去掉串左边的空格
--RIGHT()(或使用子字符串函数) 返回串右边的字符
--RTRIM()() 去掉串右边的空格
--SOUNDEX()() 返回串的SOUNDEX值
--UPPER()(Access使用UCASE()) 将串转换为大写
--COUNDEX使一个将如何文本串转换为描述其语音表示的字母数字模式的算法SOUNDEX,
--考虑了类似的发音字符和音节,
--使得能对串进行发音比较而不是字母比较。
--SELECT cust_name, cust_contact FROM Customers WHERE cust_contact = 'Michael Green';
--SELECT cust_name, cust_contact FROM Customers
--WHERE SOUNDEX(cust_contact) = SOUNDEX('Michael Green');
--SELECT order_num FROM Orders WHERE DATEPART(YY, order_date) = 2004; --YY返回年份
--DATEPART()函数有两个参数,他们分别使返回的成分和从中返回成分的日期
--在主要DBMS的函数中,数值函数是最一致最统一的函数
--常用数值处理函数
--ABS() 返回一个数的绝对值
--COS() 返回一个角度的余弦
--EXP() 返回一个数的指数值
--PI() 返回圆周率
--SIN() 返回一个角度的正弦
--SQRT() 返回一个数的平方根
--TAN() 返回一个角度的正切
--聚集函数 运行在行组中,计算并返回单一值的函数
--AVG() 返回某列的平均值
--COUNT() 返回某列的行数
--MAX() 返回某列的最大值
--MIN() 返回某列的最小值
--SUM() 返回某列值之和
--SELECT AVG(prod_price) AS avg_price FROM Products;
--AVG()也可以用来确定特定列或行的平均值 如下
--SELECT AVG(prod_price) AS avg_price FROM Products WHERE vend_id = 'DLL01';
--只用于单个列 AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。
--为了获得多个列的平均值,必须使用多个AVG()函数
--NULL值 AVG()函数忽略列值为NULL的行
--COUNT()函数进行计数。可利用COUNT()确定表中行的数目或符合特定条件的行的数目。
--COUNT()函数有两种使用方式
--使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
--使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值
--SELECT COUNT(*) AS num_cust FROM Customers; --5
--SELECT * FROM Customers;
--SELECT COUNT(cust_email) AS num_cust FROM Customers; --3 忽略NULL
--SELECT COUNT(DISTINCT cust_email) AS num_cust FROM Customers;
--NULL值 如果指定列名,则指定列的值为空的行被COUNT()函数忽略,
--但如果COUNT()函数中用的是星号(*),则不忽略。
--MAX()返回指定列中的最大值。MAX()要求指定列名。
--SELECT MAX(prod_price) AS max_price FROM Products;
--对非数值数据使用MAX()
--虽然MAX()一般用来找出最大的数值或日期值,
--但许多(并非所有)DBMS允许将它用来返回任意列中的最大值,
--包括返回文本列中的最大值。在用于文本数据时,如果数据按相应的列排序,则MAX()返回最后一列。
--NULL值 MAX()函数忽略列值为NULL的行
--MIN() 返回指定列的最小值 要求指定列名
--SELECT MIN(prod_price) AS min_price FROM Products;
--对非数值数据使用MIN()
--虽然MIN()一般用来找出最小的数值或日期值,
--但许多(并非所有)DBMS允许将它用来返回任意列中的最小值,
--包括返回文本列中的最小值。
--在用于文本数据时,如果数据按响应的列排序,则MIN()返回最前面的行。
--NULL值 MIN()函数忽略列值为NULL的行。
--SUM()用来返回指定列值的和(总计)。
--SELECT SUM(quantity) AS items_ordered FROM OrderItems WHERE order_num = 20005;
--SUM()也可以用来合计计算值
--SELECT SUM(item_price * quantity) AS total_price
--FROM OrderItems WHERE order_num = 20005;
--聚集不同值
--对以上5个聚集函数都可以如下使用:
--对所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认行为)
--只包含不同的值,指定DISTINCT参数
--ALL为默认
--SELECT AVG(DISTINCT prod_price) AS avg_price FROM Products WHERE vend_id = 'DLL01';
--如果指定列名,则DISTINCT只能用于COUNT()。DISTINCT不能用于COUNT(*)。
--类似的,DISTINCT必须使用列名,不能用于计算或表达式。
--对MIN()和MAX()使用DISTINCT没有意义。
--组合聚集函数 实际上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;
--去别名
--在指定别名以及包含某个聚集函数的结果时,不应该使用表中实际的列名,可能会产生模糊的错误消息。
--分组数据 GROUP BY & HAVING
--SELECT COUNT(*) AS num_prods FROM Products WHERE vend_id = 'DLL01';
--SELECT vend_id, COUNT(*) AS num_prods FROM Products GROUP BY vend_id;
--GROUP BY重要规定
--GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制。
--如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。
--换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。
--GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。
--如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。
--SELECT vend_id, COUNT(*) AS num_prods
--FROM Products
--GROUP BY vend_id, COUNT(*);
--在用于 GROUP BY 子句分组依据列表的表达式中,不能使用聚合或子查询。
--SELECT vend_id, COUNT(*) AS num_prods
--FROM Products
--GROUP BY vend_id, num_prods; --不能使用别名
--大多数SQL实现不允许GROUP BY列带有长度可变的数据类型(如文本或备注型字段)。
--除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出。
--如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,他们将分为一组。
--GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
--ALL子句 有些DBMS支持GROUP BY ALL子句。
--这个子句可用来返回所有的分组,即使是没有匹配行的分组也返回(在此情况下,聚集将返回NULL)。
--通过相对位置指定列 根据SELECT列表中的位置指定GROUP BY的列。
--例如,GROUP BY 2, 1可表示按选择的第二个列分组,然后再按第一个列分组。
--过滤分组
--WHERE过滤的指定的是列而不是分组。
--目前为止所学过的所有类型的WHERE子句都可以 用HAVING来替代。
--唯一的差别是WHERE过滤行,而HAVING过滤分组。
--HAVING支持所有WHERE操作符 他们的句法是相同的,只是关键字有差别。
--SELECT * FROM Orders;
--SELECT cust_id, COUNT(*) AS Orders FROM Orders GROUP BY cust_id HAVING COUNT(*) >= 2;
--正如所见,这里WHERE子句不起作用,因为过滤是基于分组聚集值而不是特定行值的。
--HAVING和WHERE的差别
--这里有另一种理解方法,WHERE再数据分组前进行过滤,HAVING再数据分组后进行过滤。
--这是一个重要的区别,WHERE排除的行不包括在分组中。
--这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。
--列出具有两个以上、价格为4以上的产品的供应商:
--SELECT vend_id, COUNT(*) AS num_prods
--FROM Products
--WHERE prod_price >= 4
--GROUP BY vend_id HAVING COUNT(*) >= 2;
--SELECT vend_id, COUNT(*) AS num_prods
--FROM Products GROUP BY vend_id HAVING COUNT(*) >= 2;
--使用HAVING和WHERE
--HAVING和WHERE非常类似,如果不指定GROUP BY,则大多数DBMS将把他们作为相同的东西对待。
--应该仅在与GROUP BY子句结合时才使用HAVING,而WHERE子句用于标准的行级过滤。
--分组和排序
--ORDER BY GROUP BY
--排序产生的输出 分组行。但输出可能不是分组的顺序
--任意列都可以使用(甚至非选择的列也可以使用) 只可能使用选择列或表达式列,而且必须使用每个选择列表达式
--不一定需要 如果与聚集函数一起使用列(或表达式),则必须使用
--SELECT order_num, COUNT(*) AS items
--FROM OrderItems GROUP BY order_num HAVING COUNT(*) >= 3;
--SELECT order_num, COUNT(*) AS items
--FROM OrderItems GROUP BY order_num HAVING COUNT(*) >= 3 ORDER BY items, order_num;
--至今为止所学过的子句
-- SELECT子句及其顺序
--子句 说明 是否必须使用
--SELECT 要返回的列或表达式 是
--FROM 从中检索数据的表 仅在从表选择数据时使用
--WHERE 行级过滤 否
--GROUP BY 分组说明 仅在按组计算聚集时使用
--HAVING BY 输出排序顺序 否
--使用子查询
--SELECT order_num FROM OrderItems WHERE prod_id = 'RGAN01';
--SELECT cust_id FROM Orders WHERE order_num IN (20007, 20008);
--SELECT cust_id
--FROM Orders
--WHERE order_num IN (SELECT order_num
--FROM OrderItems
--WHERE prod_id = 'RGAN01');
--格式化SQL 包含子查询的SELECT语句难以阅读和调试,特别是它们较为复杂时更是如此。
--如上所示把子查询分解为多行并且适当地进行缩进,能极大地简化子查询地使用。
--SELECT cust_name, cust_contact
--FROM Customers WHERE cust_id IN ('1000000004', '1000000005');
--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 = 'RGAN01'));
--可见,在WHERE子句中使用子查询能够编写功能很强并且很灵活地SQL语句。
--对于能嵌套地子查询地数量没有限制,不过在实际使用时由于性能地限制,不能嵌套太多地子查询。
--只能是单列 作为子查询地SELECT语句只能查询单个列。企图检索多个列将返回错误。
--SELECT COUNT(*) AS orders FROM Orders WHERE cust_id = '1000000001';
--SELECT cust_name, cust_state,
--(SELECT COUNT(*)
-- FROM Orders
-- WHERE Orders.cust_id = Customers.cust_id) AS orders
-- FROM Customers
-- ORDER BY cust_name;
--子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使用了完全限定列名。
--即:表名和列名有一个句点分隔。
--SELECT cust_name, cust_state,
--(SELECT COUNT(*)
-- FROM Orders
-- WHERE cust_id = cust_id) AS orders
-- FROM Customers
-- ORDER BY cust_name;
--SELECT *
--FROM Orders
--WHERE Orders.cust_id = Customers.cust_id;
--无法绑定由多个部分组成的标识符 "Customers.cust_id"。