子查询
子查询是嵌套在其他查询里的查询,比如下面的例子
SELECT product_name, cnt_product
FROM (SELECT product_name, COUNT(*) AS cnt_product
FROM product
GROUP BY product_name) AS ProductSum;
子查询可以应用在任何需要其结果的地方,比如在其之上进一步筛选,或者作为筛选条件(WHERE 或 IN)都可以。
- 子查询作为内层查询会首先执行;
- 使用子查询需要设定好名称,使不使用 AS 关键字都是可以的(Oracle 不允许 AS)。
标量子查询
标量子查询就是只返回一行一列的结果的子查询。主要是应用在需要使用常数或列名的地方(比如 WHERE 中不允许使用聚合函数,就可以使用标量子查询规避这个问题),特别是=或<>这种需要单一值的比较运算符之中。
关联子查询
关联子查询是在需要细分的组内进行比较时,所需要的操作。
比如,某表中商品分若干类,要筛选出价格高于对应类平均价格的商品信息,可以使用以下操作
SELECT product_type, product_name, sale_price
FROM Product AS P1
WHERE sale_price > (SELECT AVG(sale_price)
FROM Product AS P2
WHERE P1.product_type = P2.Product_type
GROUP BY product_type);
关键点在于在子查询中添加的 WHERE 子句的条件。
连结
在数据检索时,可以使用连结功能从一张以上的表中检索数据。
关键词:主键;外键;关系;可伸缩性
简单连结
SELECT product_name, vend_name
FROM products, vendors
WHERE products.products_id = vendors.vend_id;
- 如果不使用 WHERE 指定配对的主键和外键,连结的输出结果是两个表的笛卡尔积
也可以连结多张表,如
SELECT product_name, vend_name, quantity
FROM products, vendors, orderitems
WHERE vendors.vend_id = products.products_id
AND orderitems.products_id = products.products_id;
使用 JOIN 和 ON 进行连结
更规范的连结方法为下面这种
SELECT product_name, vend_name
FROM products JOIN vendors
ON products.products_id = vendors.vend_id;
SQL支持的连结方法有内连结(INNER JOIN,默认)、外连结(OUTER JOIN)、左连结(LEFT JOIN)、右连结(RIGHT JOIN)四种。
- 不使用 ON 指定连结键的话,结果依然是输出笛卡尔积。
组合查询
多数SQL允许执行多个查询,并将结果作为单个查询结果查询。多数情况下,组合查询达到的效果也能用WHERE子句达到,但是这两者在不同情况下的性能不同,所以应该分别尝试,确定选择哪一种。
使用UNION创建组合查询
SELECT vend_id, prod_id, prod_price
FROM products
where prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
where vend_id IN (1001, 1002);
- 组合查询要求每个查询必须包含相同的列,但各个列的次序可不必相同。
- UNION返回的是多个查询语句的并集,其中如果有重复的,将会去重。如果不想要去重,可以使用 UNION ALL。
- 可以对最终查询结果进行排序,但只能有一条ORDER BY语句,放在最后。
谓词
之前用过的各种比较运算符,比如 =、<、> 等,其正式名称就是谓词。而谓词的本质是一种返回值为布尔值的函数。
下面介绍几种常用的谓词。
LIKE:字符串的部分一致查询
在下文文本相关操作中叙述。
BETWEEN:范围查询
SELECT product_name, sale_price
FROM Product
WHERE sale_price BETWEEN 100 AND 1000;
注意 BETWEEN 返回结果包含100和1000这两个边界值。如不想包括边界值,则必须使用 < 和 >。
IS NULL、IS NOT NULL:判断空值
SELECT product_name, sale_price
FROM Product
WHERE product_name IS NOT NULL;
IN:匹配多个值
如果在筛选时要筛选出满足若干个特定值的结果,可以用 OR 书写多行的条件判断,更简单的方法是使用 IN 谓词来匹配一个列表。
SELECT product_name, sale_price
FROM Product
WHERE sale_price IN (100, 200, 300);
- 与之相对的,还有 NOT IN 来进行反向匹配;
- IN 和 NOT IN 都无法匹配空值。
文本相关操作
使用LIKE进行通配搜索
SELECT product_id, product_name
FROM products
WHERE product_name LIKE 'jet%';
进行通配搜索可以使用通配符进行模糊匹配,以下列出常见的几种通配符:
- % :匹配任意个数的任意字符;
- _ :匹配单个任意字符。
使用REGEXP应用正则表达式
SELECT product_id, product_name
FROM products
WHERE product_name REGEXP '^[0-9\\.]';
使用CONCAT拼接字符串
SELECT CONCAT(product_name, '(', produt_country, ')')
FROM products;
使用SUBSTR进行字符串截取
SELECT SUBSTR(product_name, 3, 5)
FROM products;
截取字符串从第3位开始长度为5的字串。
其他常见的文本处理函数
函数 | 说明 |
---|---|
Left() | 返回串最左边的字符 |
Right() | 返回串最右边的字符 |
Length() | 返回串的长度 |
Locate() | 返回字串的出现位置 |
SubString() | 返回子串的字符 |
Lower() | 将串转换为大写 |
Upper() | 将串转换为小写 |
Soundex() | 返回串的SOUNDEX值 |
RTrim() | 去除串右边所有空格 |
LTrim() | 去除串左边所有空格 |
Trim() | 去除串两边所有空格 |
关于 Locate() 和 SubString() 的使用,可见下:
- Locate(substr, str, pos):返回字串在字符串中第一次出现的位置,如果串中没有该字串,返回0。默认从串开头开始搜索,如果设置了pos参数,则返回其在pos位置后第一次出现的位置(依然记字符串开头为1号位置)。
- SubString(str, pos, len):截取字符串从pos位置之后的子串,默认截取到字符串最后,设置len参数可设定要截取字串的长度。
- 另一个可以返回字串位置的函数是 Position(),其使用方法为 Position(substr IN str)。
全文本搜索
MySQL只有部分数据库引擎支持全文本搜索。无论是正则还是通配符,他们都要求MySQL尝试匹配表中所有行,当随着系统的使用行数不断增加时,这些操作会非常耗时。而且,这两者是精确匹配,不够智能化。
在创建表时使用FULLTEXT启用全文本搜索
一般在创建表时启用全文本搜索支持。
CREATE TABLE productnotes
(
node_id int NOT NULL AUTO INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
)ENGINE=MyISAM;
- ENGINE子句可以指定使用哪个数据库引擎;
- FULLTEXT可以在创建表时指定,也可以在稍后指定,但不要在导入数据时使用,这样会降低索引效率。
使用 Match() 和 Against() 进行全文本搜索
其中 Match() 指定被搜索的列,Against() 指定使用的搜索表达式
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('rabbit');
- 传递给 Match() 的值必须与 FULLTEXT 中定义的相同;
- 搜索不区分大小写,除非使用 BINARY 方式;
- 全文本搜索返回以文本匹配的良好程度排序的数据,比如上面返回的就是以rabbit一词在句中的次序排列的结果。
下面为排序的演示
SELECT note_text,
Match(note_text) Against('rabbit') AS rank
FROM productnotes;
结果生成的rank列里,显示的就是该行的等级值,它根据行中的词数、唯一词数、整个索引中词的总数及包含该词的行数等计算出来。
而由于上面的语句没有使用WHERE,所以查询结果并没有过滤,会包含很多rank为0的行(即没有包含“rabbit”的行)。
查询扩展
上面的查询,是精确查询包含“rabbit”一词的行,但如果想找到不一定包含“rabbit”,但却与此有关的行,就可以使用查询扩展功能。
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION);
它的原理是,先进行一次普通的全文本搜索,找出与搜索条件匹配的所有行,然后检查这些匹配行并选择所有有用的词,根据这些词再进行一次全文本搜索,得出最终的结果。
布尔文本搜索
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);
上面的语句会查询包含“heavy”,但不包含以“rope”开头的单词的行。常见的布尔通配符如下
布尔操作符 | 说明 |
---|---|
+ | 包含(词必须存在) |
- | 排除(词必须不存在) |
> | 包含且增加等级值(即rank) |
< | 包含且减少等级值 |
( ) | 把词组成子表达式 |
~ | 取消一个词的等级值 |
* | 词尾的通配符 |
“ ” | 包含一个短语 |
- 布尔方式即使在没有定义FULLTEXT索引时也可以用,但是速度会很低。
其他说明
- 在索引全文本数据时,少于四个字符的行将被忽略并排除;
- MySQL自带停用词表,这些词在索引时会被忽略。同样的,如果一个词出现在50%以上的行中,也会被忽略,但50%规则不适用于布尔搜索;
- 如果表中的函数少于三行,则全文本搜索不会返回结果;
- 词中的单引号会被忽略,如don’t会被索引为dont;
- 不具备词分隔符的语言,如汉语不能恰当地被返回搜索结果。
增删改
使用INSERT插入数据
INSERT INTO products
VALUES('pencil',100);
上面的语句简单但不安全,完整的语法为
INSERT INTO products(prod_name, price)
VALUES('pencil', 100);
- 比较推荐下面的写法,它更安全,且在表结构发生改变的时候也能继续使用;
- 它不限制写入内容的次序,且可以只插入部分列的内容(如果约束条件允许的话);
- INSERT可能限制等待处理的SELECT语句的性能。如果该数据库查询比插入更重要,可以改用INSERT LOW_PRIORITY INTO语句降低INSERT语句的优先级。UPDATE和DELETE同理,可以用LOW_PRIORITY降低优先级。
插入多行
各行之间用逗号隔开即可。
INSERT INTO products
VALUES('pencil',100), ('pen', 200);
将SELECT出来的数据插入到表中
INSERT INTO products
SELECT prod_name, price
FROM other_products;
使用UPDATE更新数据
UPDATE products
SET price = 50
WHERE prod_name = 'pencil';
- 如果省略WHERE子句,则语句将会更新表中所有行;
- 如果要更新多个列,则在SET中用逗号隔开即可,如
SET price = 50, prod_name = ‘ruler’
; - 如果用UPDATE更新多行,只要其中一行出现错误,那么整个更新操作都会被撤回。如果要使得发生错误也能继续更新下去,可以使用IGNORE关键字,即UPDATE IGNORE。
使用DELETE删除数据
DELETE FROM products
WHERE price > 50;
- 同样,如果省略WHERE,那么语句会删除表中所有行;
- 更高效的删除所有行的方法是TRUNCATE DELETE语句,它会删除整个表然后再创建一个同样的空表。
视图
从SQL的角度来看,视图和表是相同的,区别在于表中保存的是实际的数据,而视图保存的是 SELECT 语句而不实际保存数据。
视图的好处是可以复用使用较为频繁的SQL语句,简化SQL操作,且保护数据。
创建了视图后,可以用正常的查询语句来对视图进行查询。
使用 CREATE VIEW 创建视图
CREATE VIEW view_name(column_name1, column_name2, ...)
AS
<SELECT 语句>
- 创建视图时指定列名不是必须的;
- 最好不要在创建视图时使用 ORDER BY,这在某些 DBMS 中这种操作是不允许的。而即使允许,如果从该视图中检索数据时使用了 ORDER BY,那么将覆盖视图中的 ORDER BY操作(非永久性);
- 视图可以嵌套,但不允许索引和有关联的触发器和默认值;
- 视图可以和表一起使用,比如创建一条连结表和视图的二重视图。
更新视图
使用 INSERT、UPDATE 等更新视图
当视图满足以下条件时,才能对其进行增删改操作:
- 未使用分组函数(GROUP BY 或 HAVING);
- 未使用表连结;
- 未使用子查询;
- 未使用 DISTINCT 函数;
- 未使用聚集函数;
- 未创建计算列。
这是因为,视图是基于原数据创建而来的,如果更新了包括聚合、计算的列,会难以将这种更新映射到原来的表中,这就破坏了数据的一致性。而如果成功进行了更新,那么修改也会映射到原表中。
另外,部分 DBMS(如 PostgreSQL)创建视图时默认只读,需要在创建时进行设置以允许更新。事实上,从 SQL 的理念来说,并不推荐对视图进行更新。
使用 CREATE OR REPLACE VIEW 更新视图
更新视图,而不更新原数据的方法是先用 DROP 再用 CREATE。而另一种是用 CREATE OR REPLACE VIEW
,用这句语句来代替创建视图时的 CREATE VIEW
,产生的效果就是,如果要更新的视图不存在,那么将会创建一个视图;而如果要更新的视图存在,则新的视图会取代原有视图。
其他操作
删除视图
DROP VIEW view_name;
查看创建视图的语句
SHOW CREATE VIEW view_name;
事务
事务是需要在同一个处理单元中执行的一系列更新处理的集合。比如在企业管理系统里,删除一个员工就需要对人事、财务、内网权限等信息进行更新,这时候就可以将这些操作包装成一个事务。事务操作可以用来维护数据库的完整性,即保证某种操作所牵扯到的SQL语句全部被执行。事务主要管理UPDATE、INSERT、DELETE语句。
事务必须满足四个条件(即ACID特性):
- 原子性(Atomicity):一个事务中的所有操作,要么全部执行,要么全部不执行。即使事务执行到一半被强行终止,也应回滚到事务开始前的状态。
- 一致性(Consistency):在事务开始前和结束后都没有破坏数据库的完整性,即事务的处理必须符合数据库提前设置的约束和预设规则。
- 隔离性(Isolation):数据库允许并发事务,但不同事务之间执行互不干扰,互不嵌套。而且在一个事务结束前,它对其他事务而言是不可见的。事务隔离分为不同级别,包括读未提交、读提交、可重复读和串行化。
- 持久性(Durability):事务结束后,对数据的修改就是永久的,即使系统故障也不会丢失。保证持久性的常用方法如将事务的执行记录(即日志)保存在存储空间中。
创建事务
START TRANSACTION;
<DML语句>;
<DML语句>;
...
COMMIT;
- BEGIN 或 START TRANSACTION 显式地开启一个事务。但事实上这不是事务操作真正的开始(比如Oracle定义事务并不需要这一语句),标准SQL中定义了隐式开始事务处理的方法。
- COMMIT 也可以使用 COMMIT WORK,不过二者是等价的。执行到这行代码时,事务里的指令会被真正且不可逆地执行。
使用ROLLBACK回滚事务
ROLLBACK是取消事务包含的全部更新处理的结束指令。
START TRANSACTION;
<DML语句>;
<DML语句>;
...
ROLLBACK;
以上的操作会使事务中的DML语句无效化,数据库回滚到事务开始之前的状态。
SQL中的提交模式
上文说过,START TRANSACTION 语句并不是用来真正开启事务的。大部分情况下,事务在数据库建立时就已开始了。另外,COMMIT 是提交事务的语句,但在实际使用中,经常是写完一个DML语句,DBMS便将该语句执行了,即执行 SQL 语句后就会马上执行 COMMIT 操作。这是因为该DBMS默认为自动提交模式。
在自动提交模式中,每条SQL语句就是一个事务。而如果关闭了自动提交模式,则要在用户执行了COMMIT或ROLLBACK语句后,才算作一个事务。MySQL默认的提交模式为自动提交模式。
可以用 SET 来改变 MySQL 的自动提交模式
-
SET AUTOCOMMIT=0
:禁止自动提交; -
SET AUTOCOMMIT=1
:开启自动提交。
事务的隔离级别
数据库操作中,并发情况可能会出现第一类更新丢失(事务A撤销时覆盖已提交的事务B的更新)、第二类更新丢失(事务A覆盖事务B已经提交的更新)、脏读(事务A在事务B的基础上操作,但B却回滚了,那么A读到的数据就是脏数据)、不可重复读(对同一行数据读两次却得到不同结果,比如事务A正在读取时事务B却同时更新数据)、幻象读(两次SELECT执行的效果不一样)等问题。为了解决这些问题,满足事务的隔离性,需要设置事务的隔离级别。
- READ UNCOMMITTED(读未提交):一个事务可以读取另一个未提交事务的数据。
- READ COMMITTED(读提交):一个事务要等另一个事务提交后才能读取数据。
- REPEATABLE READ(重复读):两个事务同时读取一个数据,它们读到的数据都是一样的,即开始读取数据时,不再允许修改操作。
- SERIALIZABLE(序列化):最高的隔离级别,仅允许事务串行化执行,不可并行。
大部分DBMS默认为 REPEATABLE READ,而 MySQL 默认为 REPEATABLE READ。可以通过下面的语句设置当前事务隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL <隔离级别>;
事务的保存点
在事务的处理过程中,如果发生错误且回滚 ,那么整个事务对数据库的操作都将被撤销。事实上,可以通过设置多个保存点,将事务分割为几个小部分,使得一个部分的错误不至于牵扯到整个事务。
保存点设置在事务的各DML语句之间,方法为
SAVEPOINT <保存点名>;
设置了保存点后,可以使用下面的命令回滚到这个保存点之前
ROLLBACK TO <保存点名>;
使用下面的命令删除一个保存点
RELEASE SAVEPOINT <保存点名>;
索引
索引是一种特殊的查询表,可以看作指向表中数据的指针。索引能够提高 SELECT 查询和 WHERE 子句的速度,但是却降低了包含 UPDATE 语句或 INSERT 语句的数据输入过程的速度。索引的创建与删除不会对表中的数据产生影响。
索引分为两类,聚集索引和非聚集索引。
- 聚集索引:数据表的物理存储顺序本身就是按照想要的规律排列,即数据表物理顺序与索引顺序一致的索引。由于一个数据表的物理顺序只有一种,所以只能有一个聚集索引。
- 非聚集索引:独立于数据表结构的索引,可以有多个。
建立索引
CREATE [UNIQUE] [CLUSTERED|NONCLUSTERED] INDEX <索引名>
ON <表名> ( <列名> [ASC|DESC]) WHERE [筛选条件];
- 唯一索引:如果创建索引时加入了关键词UNIQUE,则该索引为唯一索引,即不存在索引值相同的两行。对于视图创建的聚集索引必须是唯一索引。
- CLUSTERED|NONCLUSTERED:用于指定创建聚集索引或非聚集索引。默认为创建非聚集索引。
- 如果是BLOB和TEXT类型,必须在列名后用括号指定 length。
在创建表时也可以直接指定索引
CREATE TABLE <表名>
...
INDEX <索引名> <列名>
...
使用ALTER添加和删除索引
有四种方式来添加数据表的索引:
-
ALTER TABLE <表名> ADD PRIMARY KEY <列名列表>
:添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。 -
ALTER TABLE <表名> ADD UNIQUE <索引名> <列名列表>
:添加唯一索引。 -
ALTER TABLE <表名> ADD INDEX <索引名> <列名列表>
:添加普通索引。 -
ALTER TABLE <表名> ADD FULLTEXT <索引名> <列名列表>
:指定了索引为 FULLTEXT ,用于全文索引。
删除索引的操作则为
ALTER TABLE <表名> DROP <索引名>
-
DROP INDEX <索引名> ON <表名>
:也可以用这种方法
存储过程
存储过程可以理解为一个封装好的函数,或者一个批处理对象,它包括为了以后的使用而保存的一条或多条SQL语句的集合。使用存储过程的好处是简单、安全、高性能。
创建存储过程
CREATE PROCEDURE <存储过程名> (参数列表)
BEGIN
<存储过程体,如一条或多条查询语句>;
END;
-
如果使用命令行编写存储过程,那么存储过程体中的分号会使命令行以为这是整个语句的分隔符,导致句法错误。解决方法是临时更改命令行实用程序里的语句分隔符
DELIMITER // CREATE PROCEDURE <存储过程名> (参数列表) BEGIN <存储过程体,如一条或多条查询语句>; END// DELIMITER ;
上面的解决方法是利用DELIMITER将分隔符定义为“//”,然后在编写完存储过程后,再将其改回分号。除”\“符号外,任何字符都可以定义为语句分隔符。
执行存储过程
CALL <存储过程名> (参数列表);
删除存储过程
DROP PROCEDURE <存储过程名> (参数列表);
关于参数(变量)
如果不定义参数列表,那么存储过程所返回的结果就直接被显示出来,而通过添加参数列表,存储过程可以将结果返回给其对应的变量。
如定义以下的存储过程
CREATE PROCEDURE productpricing(
OUT pl DECIMAL(8, 2),
OUT ph DECIMAL(8, 2),
OUT pa DECIMAL(8, 2)
)
BEGIN
SELECT Min(prod_price)
INTO pl
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT Avg(prod_price)
INTO pa
FROM products;
END;
上面的存储过程接受三个参数,而每个参数的定义为 <关键字 变量名 数据类型>
,其中关键字包含IN(传递给存储过程)、OUT(从存储过程传出)、INOUT(对存储过程传入或传出)三种。而存储过程的参数允许的数据类型与表中使用的数据类型相同,但不允许使用记录集这种数据类型。
调用以上的存储过程,方法为
CALL productpricing(@pricelow, @pricehigh, @priceavg);
- 所有MySQL变量都必须以@开始;
- 这时候,执行
SELECT @pricelow
,可以输出对应的结果。
智能存储过程
可以在一个存储过程中定义更加复杂的操作,以包括所需的业务规则和智能处理过程。比如下面的例子,以下的存储过程有三个功能:获得订单合计、把营业税有条件地添加到合计、返回合计(带或不带税)。
-- Name:ordertotal
-- Parameters: onumber = order number
-- taxable = 0 if not taxable else 1
-- ototal = order total variable
CREATE PROCEDURE ordertotal(
IN onumber INT,
IN taxable BOOLERN,
OUT ototal DECIMAL(8, 2)
) COMMENT 'Obtain order total, optionally adding tax'
BEGIN
-- Declare variable for total
DECLARE total DECIMAL(8, 2);
-- Declare tax pencentage
DECLARE taxrate INT DEFAULT 6;
-- Get the order total
SELECT SUM(item_price * quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;
-- Is this taxable?
IF taxable THEN
SELECT total + (total / 100 * taxrate) INTO total;
END IF;
-- Finally, save to out variable
SELECT total INTO ototal;
END;
这个存储过程包含许多新内容:
- SQL的注释以 ”--“ 开头;
-
COMMENT关键字可以用来给存储过程添加说明(不是必须的),这个说明可以通过
SHOW PROCEDURE STATUS
显示。 - 用DECLARE语句定义了两个局部变量,在SQL中定义变量,需要指定类型,必要时可以通过DEFAULT语句指定默认值;
- SQL的条件判断语句结构为IF - THEN,在条件判断结束后,需要END IF语句(关于条件判断,下文会再详解);
检查存储过程
要检查用来创建一个存储过程的语句,可以用
SHOW CREATE PROCEDURE <存储过程名>;
要检查数据库中包括何时、由谁创建等详细信息的存储过程列表,可以用
SHOW PROCEDURE STATUS;
可以使用LIKE指定一个过滤模式
SHOW PROCEDURE STATUS LIKE 'ordertotal';
游标
SQL检索后返回的是一组称为结果集的行,如果想得到结果集里的第一行、第十行等,可以使用游标。游标是存储在SQL服务器上的数据库查询,它不是一条SELECT语句,而是被该语句检索出来的结果集,在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据,所以游标常常用于交互式应用。
游标的使用有以下过程:
- 先声明(定义)一个游标,即定义要使用的SELECT语句;
- 声明游标后,必须打开游标以供使用;
- 对于填有数据的游标,根据需要取出(检索)各行;
- 结束使用必须关闭游标。
创建游标
CREATE PROCEDURE processorders()
BEGIN
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
END;
游标定义在一个存储过程里,用DECLARE创建,再定义相应的SELECT语句。
打开和关闭游标
用OPEN语句打开一个游标
OPEN ordernumbers;
在执行OPEN语句时,会执行查询,将查询结果储存在游标里;
用CLOSE语句关闭游标
CLOSE ordernumbers;
不需要使用游标后应该将其关闭,以释放其占用的内存和资源。如果不明确使用CLOSE关闭游标,SQL会在到达END语句时自动将其关闭。
使用游标
打开游标后,可以使用FETCH语句访问它的每一行。FETCH指定检索什么数据,以及检索出来的数据存储在什么地方。它还向前移动游标的内部行指针,使下一条FETCH语句检索下一行。
以下的例子从游标中检索第一行
CREATE PROCEDURE processorders()
BEGIN
DECLARE o INT;
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
OPEN ordernumbers;
FETCH ordernumbers INTO o;
CLOSE ordernumbers;
END;
以下的例子遍历游标,从第一行到最后一行
CREATE PROCEDURE processorders()
BEGIN
DECLARE o INT;
DECLARE done BOOLEAN DEFAULT 0;
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
OPEN ordernumbers;
REPEAT
FETCH ordernumbers INTO o;
UNTIL done END REPEAT;
CLOSE ordernumbers;
END;
其他内容
常见的日期和时间处理函数
函数 | 说明 |
---|---|
AddDate() | 增加一个日期 |
AddTime() | 增加一个时间 |
CurDate() | 返回当前日期 |
CurTime() | 返回当前时间 |
Now() | 返回当前日期和时间 |
Date() | 返回日期时间中的日期部分 |
Time() | 返回日期时间中的时间部分 |
DateDiff() | 计算两个日期之差 |
Date_Add() | 灵活的日期运算函数 |
Date_Format() | 返回一个格式化的日期或时间串 |
Year() | 返回日期中的年份部分 |
Month() | 返回日期中的月份部分 |
Day() | 返回日期中的天数部分 |
DayOfWeek() | 返回一个日期对于的星期值(星期几) |
Hour() | 返回时间中的小时部分 |
Minute() | 返回时间中的分钟部分 |
Second() | 返回时间中的秒部分 |
常见的数值处理函数
函数 | 说明 |
---|---|
Abs() | 返回一个数的绝对值 |
Exp() | 返回一个数的指数值 |
Sqrt() | 返回一个数的平方根 |
Sin() | 返回一个角度值的正弦 |
Cos() | 返回一个角度值的余弦 |
Tan() | 返回一个角度值的正切 |
Mod(x, y) | 返回x被y除后的余数 |
Rand() | 返回一个随机数 |
Pi() | 返回圆周率 |