数据库 : Mysql - 日常应用
#登录MYSQL数据库 MYSQL -u root -p #显示所有数据库 SHOW databases; #显示当前数据库与应用程序间进行了多少条连接 SHOW processlist; #使用某一数据库 USE database; #显示所有表 SHOW tables; #表结构描述 describe DESC table; #筛选表数据 #选择哪些列 SELECT prod_name, prod_price #从哪个表选 FROM products #选择的列做出什么筛选匹配 WHERE vend_id = 1003 OR vend_id = 1004 #根据什么顺序作出排序 DESC 降序 ASC 升序 ORDER BY prod_price; WHERE-------------------------- vend_id IN (......) vend_id IS NOT NULL ------------------------------------- SELECT prod_id, prod_price FROM products WHERE prod_name LIKE 'jet%' ORDER BY prod_price; ------------------------------------- WHERE prod_name LIKE '_ ton anvil' ------------------------------------- /* 你最好避免使用匹配符_ %,因为会有性能损失的问题, 尤其别在搜索的字符串前面使用。 */ #正则表达式 SELECT prod_name FROM products WHERE prod_name REGEXP '1000' ORDER BY prod_name; --------------------------------------- #模糊查询常用 SELECT prod_name FROM products WHERE prod_name LIKE '1000' ORDER BY prod_name; SELECT prod_name FROM products WHERE prod_name REGEXP '.000' ORDER BY prod_name; /* LIKE 匹配整个列。如果被匹配的文本在列值 中出现, LIKE 将不会找到它,相应的行也不被返回(除非使用 通配符)。而 REGEXP 在列值内进行匹配,如果被匹配的文本在 列值中出现, REGEXP 将会找到它,相应的行将被返回。这是一 个非常重要的差别。 */ #匹配两个串之一 SELECT prod_name FROM products WHERE prod_name REGEXP '1000|2000' ORDER BY prod_name; #匹配几个字符之一 SELECT prod_name FROM products WHERE prod_name REGEXP '[123] Ton' ORDER BY prod_name; #否定匹配,匹配这些字符除外的任何串 SELECT prod_name FROM products WHERE prod_name REGEXP '[^123] ton' ORDER BY prod_name; #匹配范围可以被指定 SELECT prod_name FROM products WHERE prod_name REGEXP '[1-9] ton' ORDER BY prod_name; #匹配特殊字符需要在其前面添加\\作为前 '.'匹配0个或1个字符 SELECT prod_name FROM products WHERE prod_name REGEXP '\\.' ORDER BY prod_name; -------------------------------------------------------------- #字符类 /* [:alnum:] [a-zA-Z0-9] [:alpha:] [a-zA-Z] [:blank:] [\\t] [:cntrl:] [ASCII 0-31和127] [:digit:] [0-9] [:graph:] 和[:print:]相同,但不包括空格 [:lower:] [a-z] [:print:] 任意可打印字符 [:punct:] 既不在[:alnum]又不在[:cntrl:]的字符 [:space:] 包括空格在内的任意空白字符(\\f\\n\\r\\t\\v) [:upper:] [A-Z] [:xdigit:] 十六进制[a-fA-F0-9] */ -------------------------------------------------------------- #重复元字符 /* * 0个或多个匹配 + 1个或多个匹配(等于{1,}) ? 0个或1个匹配(等于{0,1}) {n} 指定数目的匹配 {n,} 不少于指定数目的匹配 {n,m} 匹配数目的范围(m不超过255) */ SELECT prod_name FROM products WHERE prod_name REGEXP '\\([0-9] sticks?\\)' ORDER BY prod_name; SELECT prod_name FROM products WHERE prod_name REGEXP '[[:digit:]]{4}' ORDER BY prod_name; ------------------------------------------------------------------ /* ^ 文本的开始 $ 文本的结尾 [[:<:]] 词的开始 [[:>:]] 词的结尾 */ SELECT prod_name FROM products WHERE prod_name REGEXP '^[0-9\\.]' ORDER BY prod_name; ----------------------------------------------------------------- /* 计算字段 一般数据库中存取的数据与应用程序所要求的数据格式并不一致, 所以需要进行格式转换,而计算字段就是应用于这一用途的字段。 计算字段是运行时在SELECT中创建出来的。 */ #拼接 --例:供应商 + 地址 SELECT Concat(vend_name, '(', vend_country, ')') FROM vendors ORDER BY vend_name; #剪切空格 RTrim SELECT Concat(RTrim(vend_name), '(', vend_country, ')') FROM vendors ORDER BY vend_name; #使用别名 AS SELECT Concat(RTrim(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 = 20005; --------------------------------------------------- #函数 #函数能方便程序员编写代码,但是这样会影响代码的可移植性。 /* 1.文本处理函数 Left() 返回串左边的字符 Length() 返回串的长度 Locate() 找出串的一个子串 Lower() 将串转换为小写 LTrim() 去掉串左边的空格 Right() 返回串右边的字符 RTrim() 去掉串右边的空格 Soundex() 返回串的SOUNDEX值 SubString() 返回子串的字符 Upper() 将串转换为大写 SOUNDEX 是一个将任何文本串转换为描述其语音表示的字母数字模式的算法。 SOUNDEX 考虑了类似的发音字符和音节,使得能对串进行发音比较而不是字母比较。 以下进行该函数的使用对比 */ SELECT cust_name,cust_contact FROM customers WHERE cust_contact = 'Y. Lie'; SELECT cust_name,cust_contact FROM customers WHERE Soundex(cust_contact) = Soundex('Y. Lie'); /* 日期和时间处理函数 AddDate() 增加一个日期(天、周等) AddTime() 增加一个时间(时、分等) CurDate() 返回当前日期 CurTime() 返回当前时间 Date() 返回日期时间的日期部分 DateDiff() 计算两个日期之差 Date_Add() 高度灵活的日期运算函数 Date_Format() 返回一个格式化的日期或时间串 Day() 返回一个日期的天数部分 DayOfWeek() 对于一个日期,返回对应的星期几 Hour() 返回一个时间的小时部分 Minute() 返回一个时间的分钟部分 Month() 返回一个日期的月份部分 Now() 返回当前日期和时间 Second() 返回一个时间的秒部分 Time() 返回一个日期时间的时间部分 Year() 返回一个日期的年份部分 */ SELECT cust_id, order_num FROM orders WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30'; /* 数值处理 Abs() 返回一个数的绝对值 Cos() 返回一个角度的余弦 Exp() 返回一个数的指数值 Mod() 返回除操作的余数 Pi() 返回圆周率 Rand() 返回一个随机数 Sin() 返回一个角度的正弦 Sqrt() 返回一个数的平方根 Tan() 返回一个角度的正切 */ ------------------------------------------------------------- #聚集函数 #我们经常需要汇总数据而不用把它们实际检索出来。 /* AVG() 返回某列的平均值 COUNT() 返回某列的行数 MAX() 返回某列的最大值 MIN() 返回某列的最小值 SUM() 返回某列值之和 DISTINCT 聚焦不同值, ALL 全部值进行计算 */ SELECT AVG(prod_price) AS avg_price FROM products WHERE vend_id = 1003; SELECT COUNT(*) AS num_cust FROM customers; SELECT AVG(DISTINCT prod_price) AS avg_price FROM products WHERE vend_id = 1003; 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 语句引出,注意一点就是选择的字段如果不是 聚集函数则需要归在分组字段中 WITH ROLLUP关键字可以得到每个分组以及每个分组汇总级别 (针对每个分组)的值 */ SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id; SELECT vend_id, AVG(prod_price) AS price_avg, COUNT(*) FROM products GROUP BY vend_id; SELECT vend_id, AVG(prod_price) AS price_avg, COUNT(*) FROM products GROUP BY vend_id WITH ROLLUP; #过滤分组 SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2; #HAVING过滤的是分组后数据组,而WHERE过滤的是数据项 SELECT vend_id, COUNT(*) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2; SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING ordertotal >= 50 ORDER BY ordertotal; #SELECT子句顺序 #SELECT -- FROM -- WHERE -- GROUP BY -- #-- HAVING -- ORDER BY -- LIMIT --------------------------------------------------------------- #子查询 SELECT cust_id FROM orders WHERE order_num IN (SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'); 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语句进行筛选。 两个表的行之间映射的结果又称笛卡尔积。 */ SELECT vend_name, prod_name, prod_price FROM vendors, products WHERE vendors.vend_id = products.vend_id ORDER BY vend_name, prod_name; SELECT vend_name, prod_name, prod_price FROM vendors, products ORDER BY vend_name, prod_name; /* 目前为止所用的联结称为等值联结(equijoin),它基于两个表之间的 相等测试。这种联结也称为内部联结。其实,对于这种联结可以使用稍 微不同的语法来明确指定联结的类型。 */ #内部联结 SELECT vend_name, prod_name, prod_price FROM vendors INNER JOIN products ON vendors.vend_id = products.vend_id; #联结多张表成一张大表 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 = 20005; #注意,联结表是性能低下的原因之一。 ------------------------------------------------------------- #使用表别名 SELECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')') AS vend_title FROM vendors ORDER BY vend_name; 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 = 'TNT2'; #自联结 /* 当需要在一张表进行两次查询才能查找到正确的字段时,可以采用自联结。 如在一张商品表中寻找某样产品的产商下的所有产品。 */ SELECT prod_id, prod_name FROM products WHERE vend_id = (SELECT vend_id FROM products WHERE prod_id = 'DTNTR'); SELECT p1.prod_id, p1.prod_name FROM products AS p1, products AS p2 WHERE p1.vend_id = p2.vend_id AND p2.prod_id = 'DTNTR'; #外部联结 /* 联结没有匹配到的行 */ SELECT customers.cust_id, orders.order_num FROM customers LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id; SELECT customers.cust_id, orders.order_num FROM customers RIGHT OUTER JOIN orders ON orders.cust_id = customers.cust_id; #使用带聚集函数的联结 SELECT customers.cust_name, 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; SELECT customers.cust_name, customers.cust_id, COUNT(orders.order_num) AS num_ord FROM customers LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id GROUP BY customers.cust_id; #组合查询 /* 多数SQL查询都只包含从一个或多个表中返回数据的单条 SELECT 语 句。MySQL也允许执行多个查询(多条 SELECT 语句) ,并将结果作为单个查询结果集返回。 这 些 组 合 查 询 通 常 称 为 并 ( union ) 或 复 合 查 询 (compound query). */ SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5; SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002); >>>>>>>>>>>>>>>>>>>>> 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 默认会去除重复的行,如果想全部显示出来则使用 SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION ALL SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002); -------------------------------------------------------------- /* 并非所有的引擎都支持全文本搜索,选择引擎时需注意。 LIKE通配符搜索和正则表达式查找存在几个问题: 性能——通配符和正则表达式匹配通常要求MySQL尝试匹配表 中所有行(而且这些搜索极少使用表索引)。 因此,由于被搜索行数不断增加,这些搜索可能非常耗时。 明确控制——使用通配符和正则表达式匹配,很难(而且并不总 是能)明确地控制匹配什么和不匹配什么。例如,指定一个词必 须匹配,一个词必须不匹配,而一个词仅在第一个词确实匹配的 情况下才可以匹配或者才可以不匹配。 智能化的结果——虽然基于通配符和正则表达式的搜索提供了非 常灵活的搜索,但它们都不能提供一种智能化的选择结果的方法。 例如,一个特殊词的搜索将会返回包含该词的所有行,而不区分 包含单个匹配的行和包含多个匹配的行(按照可能是更好的匹配 来排列它们)。类似,一个特殊词的搜索将不会找出不包含该词但 包含其他相关词的行。 */ #在使用全文本搜索时,MySQL不需要分别查看每个行,不需要分别分析和处理 #每个词。MySQL创建指定列中各词的一个索引,搜索可以针对这些词进 #行。 #为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改 #变不断地重新索引。在对表列进行适当设计后,MySQL会自动进行所有 #的索引和重新索引。 #启动全文本搜索支持 CREATE TABLE productnotes ( note_id INT NOT NULL AUTO_INCREMENT, prod_id CHAR(10) NOT NULL, note_data DATE NOT NULL, note_text TEXT NULL, PRIMARY KEY(note_id), FULLTEXT(note_text), ) ENGINE = MyISM; #这里FULLTEXT索引单个列。 #不要在导入数据的时候使用FULLTEXT索引,因为更新索引需要时间。 #应该首先导入所有数据,然后再修改表,定义FULLTEXT。 #在索引之后,使用两个函数 Match() 和 Against() 执行全文本搜索, #其中 Match() 指定被搜索的列, Against() 指定要使用的搜索表达式。 SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit'); #全文本搜索会对查询结果进行排序。 SELECT note_text, Match(note_text) Against('rabbit') AS rank FROM productnotes; #布尔文本搜索是全文本搜索的一种选择模式。 ------------------------------------------------------------------ #数据插入有以下几个方式 #插入完整的行 INSERT INTO customers VALUES(NULL, 'Pep E. LaPew', '100 Main Street', 'Los Angeles', 'CA', '90046', 'USA', NULL, NULL ); #插入多行 INSERT INTO customers(cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country) VALUES( 'Pep E. LaPew', '100 Main Street', 'Los Angeles', 'CA', '90046', 'USA' ), ( 'M. Martian', '42 Galaxy Way', 'New York', 'NY', '11213', 'USA' ); #插入某些查询的结果 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; /* 提高整体性能: 数据库经常被多个客户访问,对处理什么请求以及用什么次序处理 进行管理是MySQL的任务。 INSERT操作可能很耗时(特别是有很多索引需要更新时),而且它可能 降低等待处理的 SELECT 语句的性能。 如果数据检索是最重要的(通常是这样),则你可以通过在 INSERT 和 INTO 之间添加关键字 LOW_PRIORITY ,指示MySQL 降低 INSERT 语句的优先级。 */ INSERT LOW_PRIORITY INTO UPDATE LOW_PRIORITY DELETE LOW_PRIORITY #更新操作 UPDATE customers SET cust_name = 'The Fudds', cust_email = 'elmer@fudd.com' WHERE cust_id = 10004; #删除操作 DELETE FROM customers WHERE cust_id = 10006; #删除一表后重建表 TRUNCATE TABLE ------------------------------------------------------------------- #创建表 #指定默认值,多个主键 CREATE TABLE orderitems ( order_num INT NOT NULL, order_item CHAR(10) NOT NULL, quantity INT NOT NULL DEFAULT 1, item_price DECIMAL(8,2) NOT NULL, PRIMARY KEY(order_num, order_item) ) ENGINE=InnoDB; /* 与其他DBMS一样, MySQL有一个具体管理和处理数据的内部引擎。 在你使用 CREATE TABLE 语句时,该引擎具体创建表,而在你使用 SELECT 语句或进行其他数据库处理时,该引擎在内部处理你的请求。多数时候, 此引擎都隐藏在DBMS内,不需要过多关注它。不同的是mysql打包了多种 引擎。 InnoDB 是一个可靠的事务处理引擎(参见第26章) ,它不支持全文 本搜索; MEMORY 在功能等同于 MyISAM ,但由于数据存储在内存(不是磁盘) 中,速度很快(特别适合于临时表) ; MyISAM 是一个性能极高的引擎,它支持全文本搜索(参见第18章) ,但不支持事务处理。 */ #注意: #混用引擎类型有一个大缺陷。外键不能跨引擎,即使用一 #个引擎的表不能引用具有使用不同引擎的表的外键。 ------------------------------------------------------------------ #更新表结构,通常修改表结构是错误的,因为可能影响多处接口。 ALTER TABLE vendors ADD vend_phone CHAR(20); ALTER TABLE vendors DROP CIOLUMN vend_phone; #ALTER TABLE 一种常见的用途就是定义外键。 ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num) REFERENCES orders (order_num); #删除表 DROP TABLE customers; #重命名 RENAME TABLE backup_customers TO customers, backup_vendors TO vendors, backup_products TO products; --------------------------------------------------------------------- /* 视图 视图是虚拟的表,本身并不包含任何列或数据,它包含的是SQL查询。 重用SQL语句。 简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必 知道它的基本查询细节。 使用表的组成部分而不是整个表。 保护数据。可以给用户授予表的特定部分的访问权限而不是整个 表的访问权限。 更改数据格式和表示。视图可返回与底层表的表示和格式不同的 数据。 简单地认为视图就是包装SQL查询语句的包,每次执行都会调用相应的 查询语句块。 */ 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 cust_name, cust_contact FROM productcustomers WHERE prod_id = 'TNT2'; #格式化检索出的数据 SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country),')') AS vend_title FROM vendors ORDER BY vend_name; CREATE VIEW vendorlocations AS SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country),')') AS vend_title FROM vendors ORDER BY vend_name; #用视图过滤不想要的视图 CREATE VIEW customeremaillist AS SELECT cust_id, cust_name, cust_email FROM customers WHERE cust_email IS NOT NULL; #使用视图与计算字段 SELECT prod_id, quantity, item_price, quantity*item_price AS expanded_price FROM orderitems WHERE order_num = 20005; ---------------------------------------------------------------- /* 存储过程用于将SQL操作绑定成一个执行的最小子集,要么一起成功, 要么一起失败。 */ #创建存储过程 CREATE PROCEDURE productpricing() BEGIN SELECT Avg(prod_price) AS priceaverage FROM products; END; #如果命令行实用程序要解释存储过程自身内的 ; 字符, #则它们最终不会成为存储过程的成分,这会使存储过程中的SQL出现句法 #错误。 #使用DELIMITER 来临时标记命令行实行程序的语句分隔符 DELIMITER // CREATE PROCEDURE productpricing() BEGIN SELECT Avg(prod_price) AS priceaverage FROM products; END // DELIMITER ; #调用存储过程 CALL productpricing(); #删除储存过程 DROP PROCEDURE productpricing; #带变量的存储过程 #一般存储过程是不返回结果的,而是把结果存储至变量之中。 #OUT参数用于存储结果 #IN参数用于传递参数 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; CALL productpricing(@pricelow, @pricehigh, @priceaverage); SELECT @pricelow,@pricehigh,@priceaverage; ---------------------------------------------------------------- CREATE PROCEDURE ordertotal( IN onumber INT, OUT ototal DECIMAL(8,2) ) BEGIN SELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = onumber INTO ototal; END; CALL ordertotal(20005, @total); ---------------------------------------------------------------- #存储过程一般会添加业务规则 #下面一个存储过程展示了下面几个事物 #获取订单合计 #把营业税有条件加入合计中 #返回合计 DELIMITER // #Name : ordertotal #Parameters: onumber = order number # taxable = 0 if not taxable, 1 if taxable # ototal = order total variable CREATE PROCEDURE ordertotal( IN onumber INT, IN taxable BOOLEAN, OUT ototal DECIMAL(8,2) )COMMENT 'Obtain order total,optionally adding tax.' BEGIN #Declare variable for total DECLARE total DECIMAL(8,2); #Declare tax percentage 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 #Yes,so add taxrate to the total SELECT total+(total/100*taxrate) INTO total; END IF; #And finally,save to out variable SELECT total INTO ototal; END // DELIMITER ; CALL ordertotal(20005, 0, @total); SELECT @total; CALL ordertotal(20006, 0, @total); SELECT @total; #显示用来创建一个存储过程的CREATE语句 SHOW CREATE PROCEDURE ordertotal; #获取何时由谁创建等详细信息 SHOW PROCEDURE STATUS LIKE 'ordertotal'; ----------------------------------------------------------------- /* 游标(cursor)是一个存储在Mysql服务器上的数据库查询,它不是一条 SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后, 应用程序可以根据需要滚动或浏览其中的数据。 注意,mysql的游标只能作用于存储过程(和函数)。 */ CREATE PROCEDURE processorders() BEGIN DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; OPEN ordernumbers; CLOSE ordernumbers; END; #这个过程创建游标,打开和关闭游标 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 done BOOLEAN DEFAULT 0; DECLARE o INT; DECLARE t DECIMAL(8,2); DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; /* 这条语句定义了一个 CONTINUE HANDLER ,它是在条件出现时被执行 的代码。这里,它指出当 SQLSTATE '02000' 出现时, SET done=1。 SQLSTATE'02000' 是一个未找到条件,当 REPEAT 由于没有更多的行 供循环不能继续时,出现这个条件。 */ CREATE TABLE IF NOT EXISTS ordertotals (order_num INT, total DECIMAL(8,2)); OPEN ordernumbers; REPEAT FETCH ordernumbers INTO o; CALL ordertotal(o, 1, t); INSERT INTO ordertotals(order_num, total) VALUES(o,t); UNTIL done END REPEAT; CLOSE ordernumbers; END; SELECT * FROM ordertotals; /*输出结果 +-----------+---------+ | order_num | total | +-----------+---------+ | 20005 | 158.86 | | 20009 | 40.78 | | 20006 | 58.30 | | 20007 | 1060.00 | | 20008 | 132.50 | | 20008 | 132.50 | +-----------+---------+ */ /* 触发器是Mysql响应以下任意语句而自动执行的一条Mysql语句或者是 位于BEGIN和END之间的一组语句。 DELETE INSERT UPDATE */ #创建触发器 CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT 'Product added' INTO @temp; #当对products表进行插入时触发,对每一行插入后输出Product added. #每个表最多支持6个触发器(每条INSERT,UPDATE和DELETE的之前和之后)。 #单一触发器不能与多个事件或多张表关联。 #删除触发器 DROP TRIGGER newproduct; /* INSERT触发器 在 INSERT 触发器代码内,可引用一个名为 NEW 的虚拟表,访问被 插入的行; 在 BEFORE INSERT 触发器中, NEW 中的值也可以被更新(允许更改 被插入的值) ; 对于 AUTO_INCREMENT 列, NEW 在 INSERT 执行之前包含 0 ,在 INSERT 执行之后包含新的自动生成值。 */ CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num INTO @temp; #插入数据至orders表后输出插入数据的order_num列属性。 INSERT INTO orders(order_date, cust_id) VALUES(NOW(), 10001); /* DELETE触发器 在 DELETE 触发器代码内,你可以引用一个名为 OLD 的虚拟表,访 问被删除的行; OLD 中的值全都是只读的,不能更新。 */ #删除 #在旧订单数据删除前插入新表,保存数据。 CREATE TRIGGER deleteorder BEFORE DELETE ON orders FOR EACH ROW BEGIN INSERT INTO archive_orders(order_num, order_date, cust_id) VALUES(OLD.order_num, OLD.order_date, OLD.cust_id); END; /* UPDATE触发器 在 UPDATE 触发器代码中,你可以引用一个名为 OLD 的虚拟表访问 以前( UPDATE 语句前)的值,引用一个名为 NEW 的虚拟表访问新 更新的值; 在 BEFORE UPDATE 触发器中, NEW 中的值可能也被更新(允许更改 将要用于 UPDATE 语句中的值); OLD 中的值全都是只读的,不能更新。 */ #更改NEW的值 CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state); ------------------------------------------------------------------------- /* 事务管理——要么一起完成,要么一起失败; 理清几个概念 事务( transaction )指一组SQL语句; 回退( rollback )指撤销指定SQL语句的过程; 提交( commit )指将未存储的SQL语句结果写入数据库表; 保留点( savepoint )指事务处理中设置的临时占位符(place- holder),你可以对它发布回退(与回退整个事务处理不同)。 */ SELECT * FROM ordertotals; START TRANSACTION; DELETE FROM ordertotals; SELECT * FROM ordertotals; ROLLBACK; SELECT * FROM ordertotals; #ROLLBACK 只能在一个事务处理内使用,也就是在一条 #START TRANSACTION之后 #一般的MySQL语句都是直接针对数据库表执行和编写的。这就是 #所谓的隐含提交(implicit commit),即提交(写或保存)操作是自动 #进行的。但在事务处理块中,提交需要进行明确的提交。 START TRANSACTION; DELETE FROM orderitems WHERE order_num = 20010; DELETE FROM orders WHERE order_num = 20010; COMMIT; #复杂的事务处理可能需要部分提交或回退,可以用保留点来进行操作。 SAVEPOINT delete1; ROLLBACK TO delete1; RELEASE SAVEPOINT; #让事务不自动提交 SET autocommit = 0; --------------------------------------------------------------------- /* 全球化和本地化 字符集为字母和符号的集合; 编码为某个字符集成员的内部表示; 校对为规定字符如何比较的指令 */ #使用何种字符集和校对的决定在服务器、数据库和表级进行。 SHOW CHARACTER SET; #查看所支持校对的完整列表,_ci不区分大小写,_cs区分大小写 SHOW COLLATION; #表级 #为了给表指定字符集和校对,可使用带子句的 CREATE TABLE #很少会有服务器和数据库级别的字符集和校对的设置。 CREATE TABLE mytable( columnn1 INT, columnn2 VARCHAR(10) )DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci; #查看table的字符集和校对 SHOW TABLE STATUS FROM GoodtoKnowMysql LIKE '%order%'; ---------------------------------------------------------------------- /* 安全管理 访问控制——给用户提供他们所需的访问权,且仅提供他们所需的访问权。 Mysql Administrator 提供一个图形用户界面,可用来管理用户及 账号权限。 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 在现实世界 的日常工作中,决不能使用 root 。应该创建一系列的账号,有的用于管 理,有的供用户使用,有的供开发人员使用,等等。 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ #查看用户 USE mysql; SELECT user FROM user; #创建用户 CREATE USER Rudolph_Browne IDENTIFIED BY '**********'; #重命名用户 RENAME USER Rudolph_Browne TO Harry; #删除用户 DROP USER Harry; #设置访问权限 #查看用户权限 SHOW GRANTS FOR Rudolph_Browne; #授予权限——GRANT GRANT SELECT ON GoodtoKnowMysql.* TO Rudolph_Browne; #允许用户在GoodtoKnowMysql数据库中的所有表进行SELECT操作; GRANT ALL ON GoodtoKnowMysql.* TO Rudolph_Browne; #授予所有权限 #撤销权限 REVOKE SELECT ON GoodtoKnowMysql.* FROM Rudolph_Browne; /* GRANT 和 REVOKE 可在几个层次上控制访问权限: 整个服务器,使用 GRANT ALL 和 REVOKE ALL; 整个数据库,使用 ON database.*; 特定的表,使用 ON database.table; 特定的列; 特定的存储过程。 */ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #权限表详情请参见手册或者Mysql必知必会 p213 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #简化多次授权 GRANT SELECT, INSERT, UPDATE, DELETE ON GoodtoKnowMysql.* TO Rudolph_Browne; #更改用户口令 SET PASSWORD FOR Rudolph_Browne = Password('*********'); #更改自己口令 SET PASSWORD = Password('**********'); --------------------------------------------------------------------- #数据库维护 /* 备份数据 像所有数据一样,MySQL的数据也必须经常备份。由于MySQL数据 库是基于磁盘的文件,普通的备份系统和例程就能备份MySQL的数据。 但是,由于这些文件总是处于打开和使用状态,普通的文件副本备份不 一定总是有效。 下面列出这个问题的可能解决方案。 使用命令行实用程序 mysqldump 转储所有数据库内容到某个外部 文件。在进行常规备份前这个实用程序应该正常运行,以便能正 确地备份转储文件。 可用命令行实用程序 mysqlhotcopy 从一个数据库复制所有数据 (并非所有数据库引擎都支持这个实用程序) 。 可以使用MySQL的 BACKUP TABLE 或 SELECT INTO OUTFILE 转储所 有数据到某个外部文件。这两条语句都接受将要创建的系统文件 名,此系统文件必须不存在,否则会出错。数据可以用 RESTORE TABLE 来复原。 */ #首先刷新未写数据 为了保证所有数据被写到磁盘(包括索引 #数据),可能需要在进行备份前使用 FLUSH TABLES 语句。
#导出整个数据库
mysqldump -u 用户名 -p 数据库名 > 导出的文件名
#导出数据库中指定表
mysqldump -u 用户名 -p 数据库名 --tables table_name1 table_name2 table_name3 > db_script.sql
Rudolph Browne,
an idealist and optimist.