本文根据书籍《sql必知必会》,整理而成。
基本概念
数据库 database:保存有组织的数据的容器,通常是一个文件或一组文件。
数据库管理系统 DBMS:又称数据库软件,数据库是通过 DBMS 创建和操纵的容器。
表 table:某种特定类型数据的结构化清单。
模式 schema:关于数据库和表的布局及特性的信息。
列 column:表中的一个字段。所有的表都是由一个或多个列组成的。
行 row:表中的一个记录,有时又称为数据库记录 record。
主键 primary key:一列(或一组列),其值能够唯一标识表中每一行。
关键字 keyword:作为 SQL 组成部分的保留字。
子句 clause:SQL 语句由子句构成,有些子句是必需的,有些则是可选的。一个子句通常由一个关键字加上所提供的数据组成。例如 SELECT 语句中的 FROM 子句。
SQL 是结构化查询语言(structured query language)的缩写。SQL 是一种专门用来与数据库沟通的语言。
检索数据
基本查询用 SELECT 语句
SELECT DISTINCT prod_id, prod_name FROM Products LIMIT 5 OFFSET 5;
注意:DISTINCT 关键字作用于所有的列。LIMIT 5 OFFSET 5 指示 MySQL 等 DBMS 返回从第 5 行起的 5 行数据。第一个数字是指从哪儿开始,第二个数字是检索的行数。
排序数据
SELECT prod_id, prod_price, prod_name FROM Products ORDER BY prod_price DESC, prod_name;
注意:ORDER BY 子句必须是 SELECT 语句中的最后一条子句。同时使用 ORDER BY 和 WHERE 时,应该让 ORDER BY 位于 WHERE 之后。
过滤数据
filter condition 提取表数据的子集。
可以通过
- 关系运算 >=< 空值检查 IS NULL
- 逻辑运算 AND NOT IN NOT 等
来过滤数据。
关键字 DISTINCT 关键字,指示数据库只返回不同的值。DISTINCT 关键字作用于所有的列。
搜索数据
通配符 wildcard:用来匹配值的一部分的特殊字符。
搜索模式 search pattern:由字面值、通配符或两者组合构成的搜索条件。
谓词 predicate:操作符何时不是操作符?答案是,它作为谓词时。从技术上说,LIKE 是谓词而不是操作符。虽然最终结果是相同的。
常用的通配符有百分号 % 下划线 _ 方括号 [ ] 等。
计算字段
拼接字段,concat 就是一个函数
SELECT Concat( vend_name, ' (', vend_country, ')' ) AS vend_title FROM Vendors ORDER BY vend_name;
执行算术计算
SELECT prod_id, quantity, item_price, quantity * item_price AS expanded_price FROM OrderItems WHERE order_num = 20008;
其他算术运算符也可以使用。
汇总数据
首先讲讲函数,函数在多种编程语言里面皆有定义,SQL 中定义和它们差不多。
函数主要分为文本处理函数、日期和时间处理函数、数值处理函数。重点是聚集函数。
聚集函数 aggregate function:对某些行运行的函数,计算并返回一个值。常用的有:
- AVG 求平均值,例如:SELECT AVG(prod_price) AS avg_price FROM Products;
- COUNT 计数,例如:SELECT COUNT(*) AS num_cust FROM Customers;
- MAX MIN 最大值和最小值,例如:SELECT MAX(prod_price) AS max_price FROM Products;
- SUM 指定列的和,例如:SELECT SUM(quantity) AS items_ordered FROM OrderItems;
上面这些函数可以组合使用。
分组数据
汇总表内容的子集。主要是 GROUP BY 子句和 HAVING 子句。
例如:
SELECT vend_id, COUNT(*) AS num_prods FROM Products GROUP BY vend_id;
GROUP BY 子句指示 DBMS 分组数据,然后对每个组而不是整个结果集进行聚集。
关于 GROUP BY 的一些重要的规定。
一般用 HAVEING 子句过滤分组。HAVEING 分句非常类似于 WHERE。唯一的差别是,WHERE 过滤行,而 HAVING 过滤分组。二者句法是相同的。WHERE 在数据分组前进行过滤,HAVING 在数据分组后进行过滤。
SELECT cust_id, COUNT(*) AS orders FROM Orders GROUP BY cust_id HAVING COUNT(*) >= 2;
GROUP BY 和 ORDER BY 的组合使用。
SELECT order_num, COUNT(*) AS items FROM OrderItems GROUP BY order_num HAVING COUNT(*) >= 3 ORDER BY items, order_num;
注意子句的顺序。
子查询
子查询 subquery,即嵌套在其他查询中的查询。在 SELECT 语句中,子查询总是从内向外处理。
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' ) );
作为计算字段使用子查询。
SELECT cust_name, cust_state , ( SELECT COUNT(*) FROM Orders WHERE Orders.cust_id = Customers.cust_id ) AS orders FROM Customers ORDER BY cust_name;
以上是常见的子查询。
组合查询
在数据查询中执行联结表 join。
笛卡儿积 cartesian product:由没有联结条件的表返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。
例如:SELECT vend_name, prod_name, prod_price FROM Vendors, Products;
这样查询的结果一般不是我们想要的。
内联结
等值联结 equijoin:又称内联结 inner join,它基于两个表之间的相等测试。
带条件的联结,这是简单语法
SELECT vend_name, prod_name, prod_price FROM Vendors, Products WHERE Vendors.vend_id = Products.vend_id;
带条件的联结,这是标准语法
SELECT vend_name, prod_name, prod_price FROM Vendors INNER JOIN Products ON Vendors.vend_id = Products.vend_id;
注意 inner join 可以多次使用连接多个表。
SELECT prod_name, vend_name, prod_price, quantity FROM Products INNER JOIN Vendors ON Products.vend_id = Vendors.vend_id INNER JOIN OrderItems ON OrderItems.prod_id = Products.prod_id WHERE order_num = 20007;
联结多个表
SELECT prod_name, vend_name, prod_price, quantity FROM OrderItems, Products, Vendors WHERE (Products.vend_id = Vendors.vend_id AND OrderItems.prod_id = Products.prod_id AND order_num = 20007);
表别名:表别名只能在查询执行中使用。与列别名不一样,表别名不返回到客户端。
自联结
self-join
SELECT c1.cust_id, c1.cust_name, c1.cust_contact FROM Customers c1, Customers c2 WHERE c1.cust_name = c2.cust_name AND c2.cust_contact = 'Jim Jones';
许多 DBMS 处理联结远比处理子查询快得多。
自然联结
natural join
SELECT C.*, O.order_num, O.order_date, OI.prod_id, OI.quantity , OI.item_price FROM Customers C, Orders O, OrderItems OI WHERE (C.cust_id = O.cust_id AND OI.order_num = O.order_num AND prod_id = 'RGAN01');
无论何时对表进行联结,应该至少有一列不止出现在一个表中(被联结的列)。标准的联结返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次。
外联结
outer join
这是左联结
SELECT Customers.cust_id, Orders.order_num FROM Customers LEFT JOIN Orders ON Customers.cust_id = Orders.cust_id;
这是右联结
SELECT Customers.cust_id, Orders.order_num FROM Customers RIGHT JOIN Orders ON Orders.cust_id = Customers.cust_id;
许多联结将一个表中的行与另一个表中的行相关联,但有时候需要包含没有关联行的那些行。
利用 UNION,可以把多条查询的结果作为一条组合查询返回。
内联结是两张表中具有数据对应时才会产生一行记录。外联结则是以主表为准根据附表产生对应的记录。
插入更新删除数据
插入数据
INSERT INTO Customers (cust_id, cust_name, cust_address, cust_city, cust_state , cust_zip, cust_country, cust_contact, cust_email) VALUES ('1000000006', 'Toy Land', '123 Any Street', 'New York', 'NY' , '11111', 'USA', NULL, NULL);
插入检索出的数据
INSERT INTO Customers (cust_id, cust_contact, cust_email, cust_name, cust_address , cust_city, cust_state, cust_zip, cust_country) SELECT cust_id, cust_contact, cust_email, cust_name, cust_address , cust_city, cust_state, cust_zip, cust_country FROM CustNew;
上面的 INSERT SELECT 中 SELECT 语句可以包含 WHERE 子句,以过滤插入的数据。
INSERT 通常只插入一行。要插入多行,必须执行多个 INSERT 语句。INSERT SELECT 是个例外,它可以用一条 INSERT 插入多行,不管 SELECT 语句返回多少行,都将被 INSERT 插入。
从一个表复制到另一个表
CREATE TABLE CustCopy AS SELECT * FROM Customers;
更新数据
UPDATE customers SET cust_email = 'kim@thetoystore.com' WHERE cust_id = '1000000005';
删除数据
DELETE FROM Customers WHERE cust_id = '1000000006';
视图
视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。
因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌套了视图,性能可能会下降得很厉害。因此,在部署使用了大量视图的应用前,应该进行测试。
创建视图
CREATE VIEW ProductCustomers AS SELECT cust_name, cust_contact, prod_id FROM Customers, Orders, OrderItems WHERE Customers.cust_id = Orders.cust_id AND OrderItems.order_num = Orders.order_num;
视图的查询和普通的 SELECT 语句一样。
存储过程
存储过程就是为以后使用而保存的一条或多条 SQL 语句。可将其视为批文件,虽然它们的作用不仅限于批处理。
事务处理
使用事务处理 transaction processing,通过确保成批的 SQL 操作要么完全操作,要么完全不执行,来维护数据库的完整性。
事务处理相关的术语:
- 事务 transaction 指一组 SQL 语句;
- 回退 rollback 指撤销指定 SQL 语句的过程;
- 提交 commit 指将未存储的 SQL 语句结果写入数据库表;
- 保留点 savepoint 指事务处理中设置的临时占位符 placeholder,可以对它发布回退(与回退整个事物处理不同)。
事务处理用来管理 INSERT UPDATE DELETE 语句。
游标
游标 cursor 是一个存储在 DBMS 服务器上的数据库查询,它不是一条 SELECT 语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。
有时,需要在检索出来的行中前进或后退一行或多行,这就是游标的用途所在。
高级 SQL 特性
约束
约束 constraint:管理如何插入或处理数据库的规则。
主键 primary key:是一种特殊的约束,用来保证一列(或一组列)中的值是唯一的,而且永不改动。
外键是表中的一列,其值必须列在另一表的主键中。外键是保证引用完整性的极其重要的部分。
唯一约束 UNIQUE 可以用于限制某一列的值不重复。
检查约束用来保证一列(或一组列)中的数据满足一组指定的条件:
- 检查最小或最大值。例如,防止 0 个物品的订单;
- 指定范围。例如,保证发货日期大于等于今天的日期;
- 只允许特定的值。
索引
创建索引
CREATE INDEX prod_name_ind ON PRODUCTS (prod_name);
触发器
触发器是特殊的存储过程,它在特定的数据库活动发生时自动执行。触发器可以与特定表上的 INSERT UPDATE DELETE 相关联。
综合查询:
显示所有的库:show database;
使用名为 test 的库:use test;
显示库中所有的表:show tables;
显示表的所有信息:describe pet;
参考: