SQL必知必会
(一)查询数据
第一课 了解SQL
sql是语言,mysql是DBMS/应用程序。
第二课 检索数据SELECT
可理解为取列。
2.1 检索单个列
SElECT prod_name
FROM Products;
2.2 检索多个列
SElECT prod_id, prod_name, prod_price
FROM Products;
2.3 检索所有列
SELECT *
FROM Products;
2.4 检索不同的值
SELECT DISTINCT vend_id
FROM Products;
DISTINCT:作用于所有列,只返回不同的值。
(与ORDER BY的DESC区分)
2.5 限制结果
SELECT prod_name
FROM Products
LIMIT 5;
LIMIT 5:返回不超过5行的数据。
SELECT prod_name
FROM Products
LIMIT 5 OFFSET 5;
LIMIT 5 OFFSET 5:返回从第5行(下标为4)起的最多5行数据。
2.6 使用注释
SELECT * -- commands
FROM Products; /* commands */
第三课 排序检索数据
3.1 按单列排序
SELECT prod_name
FROM Products
ORDER BY prod_name;
ORDER BY:按列排序;需在语句的最后。
3.2 按多列排序
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price, prod_name;
多个则按出现次序,确定排序的先后次序/优先级。
3.3 按列位置排序
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY 2, 3;
2, 3:指第二列prod_price和第三列prod_name,相当于3.2的略写版。
3.4指定排序方向
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC;
ORDER BY默认是升序ASC,可用DESC实现降序。
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC, prod_name;
只对prod_price降序。
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC, prod_name DESC;
想对所有指定列降序,需要分别指定。
(与DISTINCT区分)
第四课 过滤数据
可理解为取行。
4.1 使用WHERE子句
WHERE与ORDER BY一起使用时,ORDER BY放最后。
4.2 WHERE子句操作符
4.2.1 检查单个值
注意判断相等只用 一个“=” !
SELECT prod_name, prod_price
FROM Products
WHERE prod_price < 10;
4.2.2 不匹配检查
SELECT vend_id, prod_name
FROM Products
WHERE vend_id <> 'DLL01';
注意⚠️:
1、<>与!=一样,均表示不等于。
区别在<>支持的DBMS比较多(mysql是两者都支持!)
2、值为字符串时,需要单引号扩起来。
4.2.3 范围值检查
BETWEEN a AND b
SELECT prod_name, prod_price
FROM Products
WHERE prod_price BETWEEN 5 AND 10;
4.2.4 空值检查
a IS NULL
SELECT prod_name
FROM Products
WHERE prod_price IS NULL;
检查空字段(是空不是0!)
第五课 高级数据过滤
5.1 AND操作符
xxx
WHERE vend_id = 'DLL01' AND prod_price <= 4;
5.2 OR操作符
xxx
WHERE vend_id = 'DLL01' OR prod_price <= 4;
AND与OR逻辑与C++&&||相似,也有“逻辑短路”;
并且AND优先级大于OR。
5.3 IN操作符
xxx
WHERE vend_id IN ('DLL01', 'BRS01');
IN可以代替多个OR,效率也高!
5.4 NOT操作符
xxx
WHERE NOT vend_id = 'DLL01';
也可以用 != / <>代替。
但是在复杂语句中NOT有优势。
第六课 用通配符进行过滤
6.1 LIKE操作符
但其实LIKE是谓词。
6.1.1 %通配符
表示任意长度任意字符。
(可0但不可NULL!)
xxx
WHERE prod_name LIKE 'Fish%';
6.1.2 _通配符
表示单个字符。
xxx
WHERE prod_name LIKE '__ inch teddy bear';
__:两个_表示2个任意字符。
6.2 通配符使用技巧
通配符更加耗时!
1、不要过度使用。
2、不要放在搜索的开始处(最慢)。
第七课 创建计算字段
7.1 拼接字段
SELECT CONCAT(vend_name, '(', vend_country, ')')
FROM Vendors
ORDER BY vend_name;
SELECT RTRIM(vend_name)
FROM Vendors;
SELECT CONCAT(vend_name, '(', vend_country, ')')
AS vend_title
FROM Vendors
ORDER BY vend_name;
1、CONCAT:mysql拼接函数。
2、RTRIM:去除右侧空格;TRIM则去除两侧空格。
3、AS:别名alias,将拼接后的字段赋予别名,方便客户端引用。
(用别名alias是个好习惯!)
7.2 算术计算
SELECT prod_id,
quantity,
item_price,
quantity * item_price AS expanded_price
FROM OrderItems
WHERE order_num = 20008;
可以进行加减乘除后as别名。
第八课 使用函数处理数据
8.1 函数
SQL函数是不可移植的,即不用DBMS都有其特定的函数。
8.2 常见函数
8.2.1 文本处理函数
名称 | 调用示例 | 示例结果 |
---|---|---|
LEFT | LEFT(‘abc123’, 3) | abc |
RIGHT | RIGHT(‘abc123’, 3) | 123 |
LENGTH | LENGTH(‘abc’) | 3 |
LOWER | LOWER(‘ABC’) | abc |
UPPER | UPPER(‘abc’) | ABC |
TRIM | LTRIM(’ abc ') | abc |
SUBSTRING | SUBSTRING(‘abc123’, 2, 3) | bc1 |
CONCAT | CONCAT(‘abc’, ‘123’, ‘xyz’) | abc123xyz |
SOUNDEX | SOUNDEX(‘helle’) | hello |
SOUNDEX根据文本发音实现模糊音匹配。
8.2.2 日期与时间处理函数
SELECT order_num
FROM Orders
WHERE YEAR(order_data) = 2012;
YEAR:提取年份。
8.2.3 数值处理函数
名称 | 功能 |
---|---|
ABS | 绝对值 |
RAND | 0-1随机数 |
ROUND(x, y) | x四舍五入,保留y位小数 |
MOD | 取余 |
第九课 汇总数据
9.1 聚集函数
计算并返回一个值。
五种聚合函数:AVG、COUNT、MAX、MIN、SUM
9.1.1 AVG()函数
注意⚠️:只能用于单列,并且忽略NULL行。
SELECT AVG(prod_price) AS avg_price
FROM Products;
9.1.2 COUNT()函数
两种方式:
COUNT(*)
统计所有行数(包括NULL)COUNT(column)
统计特定列有值的行数(不包含NULL)
9.1.3 MAX()函数
9.1.4 MIN()函数
9.1.5 SUM()函数
注意⚠️:除了COUNT(*),其他均忽略NULL行。
9.2 聚集不同值
SELECT AVG(DISTINCT prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';
DISTINCT:忽略重复值。
注意⚠️:COUNT(*)不可用。
9.3 组合聚集函数
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;
第十课 分组数据
10.1 数据分组
涉及两种SELECT子句:
- GROUP BY
- HAVING
10.2 创建分组
GROUP BY:“排序”并分组(注意不一定会正确排序)
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id;
Output:
Vend_id | num_prods |
---|---|
BRS01 | 3 |
DLL01 | 4 |
FNG01 | 2 |
注意⚠️:
1、顺序WHERE -> GROUP BY -> ORDER BY
2、NULL也归为一组
3、可嵌套
4、不可用别名
5、SELECT的列必须也在GROUP BY中给出(除了聚集函数)
10.3 过滤分组
HAVING:过滤分组,分组后过滤
(可替换之前学的所有WHERE)
WHERE:过滤行,分组前过滤
SELECT cust_id, COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
Output:
cust_id | orders |
---|---|
1000000001 | 2 |
注意⚠️:
1、顺序WHERE -> GROUP BY -> HAVING -> ORDER BY
2、HAVING与GROUP BY搭配使用。
10.4 分组和排序
GROUP BY:分组
ORDER BY:排序
一般两者一起搭配使用,不能依赖GROUP BY来排序。
10.5 SELECT子句顺序
SELECT
->FROM
->WHERE
->GROUP BY
->HAVING
->ORDER BY
第十一课 使用子查询
11.1 子查询
查询query:一般指SELECT。
子查询subquery:嵌套查询。
11.2 子查询进行过滤
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'));
注意⚠️:
1、子查询总是由内向外处理。
2、子查询只能单列
11.3 子查询作为计算字段
SELECT cust_name,
cust_state,
(SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;
完全限定列名:完全指定表明+列名。
第十二课 联结表
12.1 联结
联结表join
关系数据库:表之间通过某些相同的值进行关联。
12.1.1 关系表
把一个表的信息拆分成多个的优点:
1、信息不重复。
2、更新时只需更新一处。
3、数据一致性易维护。
12.2 创建联结
SELECT vend_name, prod_name, prod_price
FROM Vendors, Products
WHERE Vendors.vend_id = Products.vend_id;
注意⚠️:
1、表联结的结果是其笛卡尔积。
2、WHERE筛选出笛卡尔积的子集。
3、联结一定要用WHERE,不然会有一大堆无用信息。
12.3 内联结
内联结inner join = 等值联结equijoin
内联结独特语法(与上面👆效果一样):
SELECT vend_name, prod_name, prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;
FROM a INNER JOIN b ON condition;
12.4 联结多个表
SELECT vend_name, prod_name, prod_price, quantity
FROM OrderItems, Vendors, Products
WHERE Vendors.vend_id = Products.vend_id
AND OrderItems.prod_id = Products.prod_id
AND order_num = 20007;
12.5 联结代替子查询
多个SELECT嵌套的子查询,可以用联结来代替。
但是注意⚠️联结耗费资源比较大。
第十三课 创建高级联结
13.1 使用表别名
和列别名相似,依旧用AS。
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 = 'RGAN01'
表别名的作用:
- 简写
- 可在一条SELECT语句多次用同一个表
13.2 四种联结
13.2.1 自联结
自联结self-join:联结的两个表是同一个表。
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';
13.2.2 自然联结
自然联结natural-join:保证每个列只出现一次,因为不同的表内可以存在相同的列名。
注意⚠️:我们用的每一个内联结都是自然联结!
13.2.3 内联结
内联结inner-join:两个表之间的相等测试。
具体看12.3。
SELECT Customers.cust_id, Orders.order_num
FROM Customers INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
13.2.4 外联结
外联结outer-join:保关联失败的行。
分左外联结LEFT OUTER JOIN和右外联结RIGHT OUTER JOIN。
SELECT Customers.cust_id, Orders.order_num
FROM Customers RIGHT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
13.3 带聚集函数的联结
第十四课 组合查询
14.1 组合查询
多条SELECT查询结果组合返回。
目的:
- 多个表的查询组合起来
- 一个表的多次查询组合起来
14.2 创建组合查询
14.2.1 UNION
在各个SELECT语句中插入UNION。
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL', 'IN', 'MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';
14.2.2 UNION ALL
UNION默认删除重复行;
UNION ALL可以保留重复的行。
14.2.3 组合查询的排序
ORDER BY只能在最后的SELECT语句中出现,且只能用一次!