《MySQL必知必会》笔记(SQL练习+建表语句)

站在巨人的肩上
Standing On Shoulders Of Giants
部分转自:https://www.jianshu.com/p/294502893128
https://blog.csdn.net/qq_33704186/article/details/81909168


大概目录:
1.SQL语句学习
2.本书练习SQL案例
3.类似Oracle中的经典SQL练习案例


《MySQL必知必会》学习笔记
后面有联系SQL建表语句
学习MySQL, 便把书本中的代码练习了一遍, 以此文留个记录(图片引自豆瓣),
此书配套资料在http://forta.com/books/0672327120/网站下载





目录 · · · · · ·
第1章 了解SQL
第2章 MySQL简介
...
...
第21章 创建和操纵表
第22章 使用视图
第23章 使用存储过程
第24章 使用游标
第25章 使用触发器
第26章 管理事务处理
第27章 全球化和本地化
第28章 安全管理
第29章 数据库维护
第30章 改善性能
《MySQL必知必会》SQL文件

第3章 使用MySQL

# 使用指定的数据库
use mysql_need_know;

# 显示所有的数据库
show databases;

# 显示所有数据库中的所有表
show tables;

# 显示指定表的所有列信息
show columns from customers;
desc customers;
describe customers;

# 显示mysql服务状态信息
show status;

# 显示指定的数据库或者数据表的创建SQL语句
SHOW CREATE DATABASE mysql_need_know;
SHOW CREATE TABLE customers;

# 显示授予用户的安全权限
SHOW GRANTS;

# 显示错误信息
SHOW ERRORS;

# 显示警告信息
SHOW WARNINGs;

第4章 检索数据

 # 从指定表中查询所有的列的信息
SELECT prod_name FROM products;

# 从指定表中查询指定列的信息
SELECT prod_name FROM products;

# 从指定表中查询多个列的信息
SELECT prod_id, prod_name, prod_price FROM products;

# 去重(会应用于所有的列, 而不是只有第一列)
SELECT DISTINCT vend_id, prod_price FROM products;

# 限制查询返回的行数(一个参数为返回的行数)
SELECT prod_name FROM products LIMIT 5;
# 限制查询返回的行数(二个参数中第一个为跳过的行数, 第二个参数为要显示的行数)
SELECT prod_name FROM products LIMIT 5, 5;
# 从第0行开始取5行返回, 和上面的语句相反
SELECT prod_name FROM products LIMIT 5 OFFSET 0;

# 全限定表名和列名
SELECT products.prod_name FROM mysql_need_know.products;

第5章 排序检索数据

# 排序(默认正序)
SELECT prod_name FROM products ORDER BY prod_name;
# 正序
SELECT prod_name FROM products ORDER BY prod_name ASC;
# 逆序
SELECT prod_name FROM products ORDER BY prod_name DESC;
# 只对其前面的列名排序
SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price DESC, prod_name;


# 多列排序,会按列的顺序排,先排价格,如果有价格相同的行,这些行再按姓名排
SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price, prod_name;


# 限制和排序结合,找出指定列的最大值和最小值(LIMIT要在ORDER BY子句之后)
SELECT prod_price FROM products ORDER BY prod_price LIMIT 1;
SELECT prod_price FROM products ORDER BY prod_price DESC LIMIT 1;

第6章 过滤数据

SELECT prod_name, prod_price FROM products WHERE prod_price = 2.50;

# WHERE 子句操作符 =, !=, <>, <, <=, >, >=, BETWEEN a AND b (包含a和b)
# 大小写不区分(字符串要用小括号括起来)
SELECT prod_name, prod_price FROM products WHERE prod_name = 'fuses';

# 检测指定列是否包含null值
SELECT prod_name FROM products WHERE prod_price IS NULL;
SELECT cust_id FROM customers WHERE cust_email IS NULL;

第7章 数据过滤

# 多条件WHERE过滤
# AND
SELECT prod_id, prod_price, prod_name FROM products WHERE vend_id = 1003 AND prod_price <= 10;

# OR 
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id = 1002 OR vend_id = 1003;

# 组合OR和AND(下面是错误的组合方法,AND的优先级比OR要高)
SELECT prod_name, prod_price FROM products WHERE vend_id = 1002 OR vend_id = 1003 AND prod_price >= 10;

# 组合OR和AND(使用括号提升包含OR的筛选条件的优先级)
SELECT prod_name, prod_price FROM products WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;

# IN 指定条件范围
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id IN (1002, 1003) ORDER BY prod_name;
# 使用OR和上面用IN的效果一样,但是IN更快
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id = 1002 OR vend_id = 1003;
# NOT 否定后面跟的条件
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id NOT IN (1002, 1003) ORDER BY prod_name;

第8章 用通配符进行过滤

# 通配符 % 表示任何字符出现任何次数(当前是不区分大小写的,可以配置区分大小写)
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE 'jet%';
# 使用多个通配符
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '%anvil%';

SELECT prod_name FROM products WHERE prod_name LIKE 's%e';

# 注意,用%不能匹配null

# 下划线(_)匹配一个字符
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '_ ton anvil';

第9章 用正则表达式进行搜索

# 在子句中使用正则匹配
SELECT prod_name FROM products WHERE prod_name REGEXP '1000' ORDER BY prod_name;

# 使用.匹配任意一个字符
SELECT prod_name FROM products WHERE prod_name REGEXP '.000' ORDER BY prod_name;
# 区分大小写
SELECT prod_name FROM products WHERE prod_name REGEXP BINARY 'Jet' ORDER BY prod_name;
# 匹配两个串(类似OR的功能)
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;

# 错误的匹配,这等于匹配 1 或者 2 或者 3 Ton
SELECT prod_name FROM products WHERE prod_name REGEXP '1|2|3 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-5] Ton' ORDER BY prod_name;
# 匹配特殊字符(在特殊字符前加双斜杠(\\))
SELECT vend_name FROM vendors WHERE vend_name REGEXP '\\.' ORDER BY vend_name;

#匹配字符类(预定义的字符集)
# 任意字母或者数字
SELECT vend_name FROM vendors WHERE vend_name REGEXP '[[:alnum:]]' ORDER BY vend_name;
#任意字符
SELECT vend_name FROM vendors WHERE vend_name REGEXP '[[:alpha:]]' ORDER BY vend_name;
#任意数字
SELECT vend_name FROM vendors WHERE vend_name REGEXP '[[:digit:]]' ORDER BY vend_name;
#任意小写字母
SELECT vend_name FROM vendors WHERE vend_name REGEXP '[[:lower:]]' ORDER BY vend_name;
#任意大写字母
SELECT vend_name FROM vendors WHERE vend_name REGEXP '[[:upper:]]' ORDER BY vend_name;

SELECT prod_name FROM products WHERE prod_name REGEXP '\\([0-9] sticks?\\)' ORDER BY prod_name;

# 匹配连在一起的4位数字
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 'hello1' REGEXP '[0-9]';

第10章 创建计算字段

# 使用concat()函数拼接列
SELECT CONCAT(vend_name, ' (', vend_country, ')') AS vend_title FROM vendors ORDER BY vend_name;

# 使用RTRIM()函数来删除字段右边的空格
SELECT CONCAT(RTRIM(vend_name), '(', RTRIM(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;

# 常用检测方法
SELECT 3 * 2;
SELECT TRIM('abc');
SELECT NOW();

第11章 使用数据处理函数

# 转换大小写函数
SELECT vend_name, UPPER(vend_name) AS vend_name_upcase FROM vendors ORDER BY vend_name;
SELECT vend_name, LOWER(vend_name) AS vend_name_lower FROM vendors ORDER BY vend_name;

# 返回串左边和返回串右边指定位数的字符
SELECT vend_name, LEFT(vend_name, 5) AS vend_name_left FROM vendors ORDER BY vend_name;
SELECT vend_name, RIGHT(vend_name, 5) AS vend_name_right FROM vendors ORDER BY vend_name;

# 返回串的长度
SELECT vend_name, LENGTH(vend_name) AS vend_name_length FROM vendors ORDER BY vend_name;

# 返回串的子串第一次出现的位置
SELECT vend_name, LOCATE('A', vend_name) AS vend_name_locate FROM vendors ORDER BY vend_name;

# 返回子串的字符(截取子串)
SELECT vend_name, SUBSTRING(vend_name, 1, 5) AS vend_name_locate FROM vendors ORDER BY vend_name;

# 返回串的SOUNDEX值
SELECT vend_name, SOUNDEX(vend_name) AS vend_name_locate FROM vendors ORDER BY vend_name;
# 发音相近匹配
SELECT cust_name, cust_contact FROM customers WHERE SOUNDEX(cust_contact) = SOUNDEX('Y. Lie');


SELECT CURDATE(); # 当前日期
SELECT CURTIME(); # 当前时间

SELECT DATEDIFF('2018-10-10', "2018-10-11"); # 比较日期(计算日期差值)
SELECT ADDDATE(NOW(), 10); # 给指定的日期增加指定的天数
SELECT OrderId,DATEADD(day,2,OrderDate) AS OrderPayDate FROM Orders # 向OrderDate增加2天
SELECT DATE_ADD(NOW(), INTERVAL 60 SECOND) # 高精度增加时间
SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%S'); # 使用指定格式格式化日期
SELECT DATE('2018-10-10 12:12'); # 截取日期部分
SELECT TIME('2018-10-10 12:12:12'); #返回日期的时间部分
SELECT YEAR('2018-10-10 12:12:12'); #返回日期的年份部分
SELECT MONTH('2018-10-10 12:12:12'); #返回日期的月份部分
SELECT DAY('2018-10-10 12:12:12'); #返回日期的天数部分
SELECT HOUR('2018-10-10 12:12:12'); #返回日期的时针部分
SELECT MINUTE('2018-10-10 12:12:12'); #返回日期的分针部分
SELECT SECOND('2018-10-10 12:12:12'); #返回日期的秒部分

# 根据日期筛选
SELECT cust_id, order_num FROM orders WHERE order_date = '2005-09-01';
# 更可靠的根据日期筛选
SELECT cust_id, order_num FROM orders WHERE DATE(order_date) = '2005-09-01';
# 筛选一个日期范围内的结果
SELECT cust_id, order_num FROM orders WHERE DATE(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
# 更可靠的日期范围筛选
SELECT cust_id, order_num FROM orders WHERE Year(order_date) = 2005 AND Month(order_date) = 9;

# 返回0-1之间不包括1的随机数
SELECT RAND();


第12章 汇总数据

# 返回指定列的平均值
SELECT AVG(prod_price) AS avg_price FROM products;
# 返回指定列符合条件的行的平均值
SELECT AVG(prod_price) AS avg_price FROM products WHERE vend_id = 1003;

# 计算指定表的行数(包括null值行)
SELECT COUNT(*) AS num_cust FROM customers;

# 计算指定列的行数(不包括null值行)
SELECT COUNT(cust_email) AS num_cust FROM customers;

# 返回指定列的最大值(忽略null值)
SELECT MAX(prod_price) AS max_price FROM products;

# 返回指定列的最小值(忽略null值)
SELECT MIN(prod_price) AS min_price FROM products;

# 对指定列求合
SELECT SUM(quantity) AS items_ordered FROM orderitems WHERE order_num = 20005;
# 在求全函数中计算
SELECT SUM(quantity*item_price) AS total_price FROM orderitems WHERE order_num = 20005;

# 在函数中使用DISTINCT
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;

第13章 分组数据

# 使用分组计算所有供应商对应都有几个产品
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 语句中的每个列都必须在 GROUP BY 子
-- 句中给出。
--  如果分组列中具有 NULL 值,则 NULL 将作为一个分组返回。如果列
-- 中有多行 NULL 值,它们将分为一组。
--  GROUP BY 子句必须出现在 WHERE 子句之后, ORDER BY 子句之前

# 对分组汇总
SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id WITH ROLLUP;

# 使用HAVING过滤分组
SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2;

# 查询出具有2个或以上,价格为10或以上产品的供应商
SELECT vend_id, COUNT(*) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2;

SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id HAVING COUNT(*) >= 2;

# GROUP BY 和 ORDER BY 结合使用
SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50 ORDER BY ordertotal;


# SELECT子句的顺序
SELECT > FROM > WHERE > GROUP BY > HAVING > ORDER BY > LIMIT;

第14章 使用子查询

# 列出订购物品 TNT2 的所有客户
-- 方式一:分条查询
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2';
SELECT cust_id FROM orders WHERE order_num IN (20005, 20007);

-- 方法二:子查询
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 = '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;

第15章 联结表

# 联结查询(等值联结果或者内部连接)
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 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;

第16章 创建高级联结

# 在连接查询中使用别名
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 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
    c.*,
    o.order_num,
    o.order_date,
    oi.prod_id,
    oi.quantity,
    oi.item_price 
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 = 'FB';


# 外部连接(左外和右外)
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;


第17章 组合查询

# 使用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);

# 不自动取消重复行
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);

# 只能在最后一条SQL后写排序
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);
ORDER BY vend_id, prod_price;

第18章 全文本搜索

# MyISAM支持全文搜索, InnoDB不支持全文搜索
#为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引
# 创建表时使用FULLTEXT对指定的列进行索引

# 使用函数进行搜索
SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit');
# 使用LIKE进行搜索
SELECt note_text FROM productnotes WHERE note_text LIKE '%rabbit%';

# 观察搜索结果排序
SELECT note_text, Match(note_text) Against('rabbit') AS rank FROM productnotes;


# 不使用查询扩展
SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils');

# 使用查询扩展(会扫描两遍,第一遍精确查找,第二遍模糊查找)
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' IN BOOLEAN MODE);
SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);

# 搜索匹配包含词 rabbit 和 bait 的行
SELECT note_text FROM productnotes WHERE Match(note_text) Against('+rabbit +bait' IN BOOLEAN MODE);
# 没有指定操作符,这个搜索匹配包含 rabbit 和 bait 中的至少一个词的行
SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit bait' IN BOOLEAN MODE);
# 这个搜索匹配短语 rabbit bait 而不是匹配两个词 rabbit 和bait
SELECT note_text FROM productnotes WHERE Match(note_text) Against('"rabbit bait"' IN BOOLEAN MODE);
# 匹配 rabbit 和 carrot ,增加前者的等级,降低后者的等级
SELECT note_text FROM productnotes WHERE Match(note_text) Against('>rabbit <bait' IN BOOLEAN MODE);
# 这个搜索匹配词 safe 和 combination ,降低后者的等级
SELECT note_text FROM productnotes WHERE Match(note_text) Against('"+safe +(<combination)' IN BOOLEAN MODE);

第19章 插入数据

# 在指定的表中插入一行数据(INSERT语句一般不会产生输出, 但会返回影响的行数)
# 这种方式不保险, 哪里列的顺序改变了就会出错
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, cust_contact, cust_email )
VALUES
    ( 'Pep E. LaPew', '100 Main Street', 'Los Angeles', 'CA', '90046', 'USA', NULL, NULL);


# 插入一行, 只插入指定的列值, 其它为默认值或者NULL
# 没有默认值或者不能为NULl时会报错,并且插入不成功
INSERT INTO customers (cust_name) VALUES ('Jack song');

# 降低INSERT语句的优先级
INSERT LOW_PRIORITY INTO customers ( cust_name )
VALUES
    ( 'Jone Li. Main' );

# 一次插入多行数据 方式一(用分号分隔)
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' );
INSERT INTO customers ( cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country )
VALUES
    ( 'M. Martian', '42 Galaxy Way', 'New York', 'Ny', '11213', 'USA' );


# 一次插入多行数据 方式二(多行数用括号包裹,逗号分隔)
# 此技术可以提高数据库处理的性能,因为MySQL用单条 INSERT 语句处理多个插入比使用多条 INSERT语句快
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和SELECT结合插入其它表检索出来的数据
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;

第20章 更新和删除数据

# 不要省略 WHERE 子句 在使用 UPDATE 时一定要注意细心,
# 因为稍不注意,就会更新表中所有行. 

# 更新符合筛选条件的行中的指定列
UPDATE customers SET cust_email = 'elemer@fudd.com' WHERE cust_id = 10005;

# 更新多列
UPDATE customers SET cust_name = 'The Fudds', cust_email = 'elmer@fudd.com' WHERE cust_id = 10005;

# 更新多行时, 使用IGNORE忽略错误, 继续更新下去
UPDATE IGNORE customers SET cust_email = 'elemer1@fudd.com' WHERE cust_id = '10005';


# 可以用来删除指定列(可以为NULL的情况)
UPDATE customers SET cust_email = NULL WHERE cust_id = 10005;



# 在使用 DELETE 时一定要注意细心。因为稍不注意,就会错误地删除表中所有行
# 删除符合筛选条件的行
DELETE FROM customers WHERE cust_id = 10006;

# DELETE 语句从表中删除行, 甚至是删除表中所有行。但是, DELETE 不删除表本身

-- 更新和删除的指导原则
-- 前一节中使用的 UPDATE 和 DELETE 语句全都具有 WHERE 子句,这样做的
-- 理由很充分。如果省略了 WHERE 子句,则 UPDATE 或 DELETE 将被应用到表中
-- 所有的行。换句话说,如果执行 UPDATE 而不带 WHERE 子句,则表中每个行
-- 都将用新值更新。类似地,如果执行 DELETE 语句而不带 WHERE 子句,表的
-- 所有数据都将被删除。
-- 下面是许多SQL程序员使用 UPDATE 或 DELETE 时所遵循的习惯。
--  除非确实打算更新和删除每一行,否则绝对不要使用不带 WHERE
-- 子句的 UPDATE 或 DELETE 语句。
--  保证每个表都有主键(如果忘记这个内容,请参阅第15章),尽可能
-- 像 WHERE 子句那样使用它(可以指定各主键、多个值或值的范围)。
--  在对 UPDATE 或 DELETE 语句使用 WHERE 子句前,应该先用 SELECT 进
-- 行测试,保证它过滤的是正确的记录,以防编写的 WHERE 子句不
-- 正确。
--  使用强制实施引用完整性的数据库(关于这个内容,请参阅第15
-- 章),这样MySQL将不允许删除具有与其他表相关联的数据的行

第21章 创建和操纵表

# 使用SQL创建新表
CREATE TABLE customers1 (
    cust_id INT NOT NULL AUTO_INCREMENT,
    cust_name char(50) NOT NULL,
    cust_address char(50) NULL,
    cust_city char(50) NULL,
    cust_state char(5) NULL,
    cust_zip char(10) NULL,
    cust_country char(50) NULL,
    cust_contact char(50) NULL,
    cust_email char(255) NULL,
    PRIMARY KEY (cust_id)
) ENGINE=InnoDB;


# 不允许NULL值
CREATE TABLE orders1 (
    order_num   int NOT NULL AUTO_INCREMENT,
    order_date datetime NOT NULL,
    cust_id int NOT NULL,
    PRIMARY KEY (order_num)
) ENGINE=InnoDB;

# 多列主键
CREATE TABLE orderitems1 (
    order_num   int NOT NULL,
    order_item int NOT NULL,
    prod_id char(10) NOT NULL,
    quantity int NOT NULL,
    item_price decimal(8, 2) NOT NULL,
    PRIMARY KEY (order_num, order_item)
) ENGINE=InnoDB;


# 使用函数获得最后自动生成的id
SELECT LAST_INSERT_ID();


# 创建表时给默认值
CREATE TABLE IF NOT EXISTS orderitems2 (
    order_num int NOT NULL,
    order_item int NOT NULL,
    prod_id 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;


# 更新表结构(添加列)
ALTER TABLE vendors ADD vend_phone CHAR(20);

# 更新表结构(删除列)
ALTER TABLE vendors DROP COLUMN vend_phone;

# 更新表(添加外键)
ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num) REFERENCES orders (order_num);

ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_products FOREIGN KEY (prod_id) REFERENCES products (prod_id);

ALTER TABLE orders ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id) REFERENCES customers (cust_id);

ALTER TABLE products ADD CONSTRAINT fk_products_vendors FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);


##复杂的表结构更改一般需要手动删除过程,它涉及以下步骤:
--  用新的列布局创建一个新表;
--  使用 INSERT SELECT 语句(关于这条语句的详细介绍,请参阅第
--      19章)从旧表复制数据到新表。如果有必要,可使用转换函数和
--      计算字段;
--  检验包含所需数据的新表;
--  重命名旧表(如果确定,可以删除它);
--  用旧表原来的名字重命名新表;
--  根据需要,重新创建触发器、存储过程、索引和外键。


# 删除表
DROP TABLE orderitems2

# 重命名表
RENAME TABLE customers1 TO customer3;

# 同时重命名多个表
RENAME TABLE customer3 TO customers1, orderitems1 TO orderitems2;

第22章 使用视图

# 视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询


# 普通方法检索需要的数据
SELECT
    cust_name,
    cust_contact 
FROM
    customers,
    orders,
    orderitems 
WHERE
    customers.cust_id = orders.cust_id 
    AND orderitems.order_num = orders.order_num 
    AND prod_id = 'TNT2';

# 使用视图检索(假如可以把整个查询包装成一个名为 productcustomers 的虚拟表)
SELECT
    cust_name,
    cust_contact 
FROM
    productcustomers 
WHERE
    prod_id = 'TNT2';

-- 这就是视图的作用。 productcustomers 是一个视图,作为视图,它
-- 不包含表中应该有的任何列或数据,它包含的是一个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;

# 创建视图
CREATE VIEW vendorlocations AS SELECT
Concat ( RTrim( vend_name ), '(', RTrim( vend_country ), ')' ) AS vend_title 
FROM
    vendors 
ORDER BY
    vend_name;

# 在视图中查询
SELECT * FROM vendorlocations;


# 创建视图
CREATE VIEW customeremaillist AS SELECT
cust_id,
cust_name,
cust_email 
FROM
    customers 
WHERE
    cust_email IS NOT NULL;


# 检索视图
SELECT * FROM customeremaillist;

# 双WHERE子句(视图中一个, SQL中一个)
SELECT * FROM customeremaillist WHERE cust_id = 10003;


# 创建视图(和计算字段结合)
CREATE VIEW orderitemsexpanded AS SELECT
order_num,
prod_id,
quantity,
item_price,
quantity * item_price AS expanded_price 
FROM
    orderitems;

# 检索有计算字段的视图
SELECT * FROM orderitemsexpanded WHERE order_num = 20005;

-- 如果视图定义中有以下操作,则不能进行视图的更新:
--  分组(使用 GROUP BY 和 HAVING );
--  联结;
--  子查询;
--  并;
--  聚集函数( Min() 、 Count() 、 Sum() 等)
--      DISTINCT;
--  导出(计算)列

第23章 使用存储过程

# 调用存储过程并返回数据
CALL productpricing(@pricelow, @pricehigh, @priceaverage);


# 创建存储过程
CREATE PROCEDURE productpricing()
BEGIN
    SELECT Avg(prod_price) AS priceaverage FROM products;
END


# 调用存储过程
CALL productpricing();


# 为了在命令行中不出错,改变分隔符
DELIMITER //
CREATE PROCEDURE productpricing1()
BEGIN
    SELECT Max(prod_price) AS pricehigh FROM products;
END //
DELIMITER ;

CALL productpricing1();


# 删除存储过程
DROP PROCEDURE IF EXISTS productpricing1 ;


# 使用OUT参数
CREATE PROCEDURE productpricingwithavg(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 productpricingwithavg(@pricelow, @pricehigh, @priceaverage);
# 显示出来 
SELECT @pricelow;
SELECT @pricelow, @pricehigh, @priceaverage;


# 使用IN OUT参数
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);
SELECT @total;

# 可以用不同的参数反复调用存储过程
CALL ordertotal(20009, @total);
SELECT @total;


# 一个更智能的存储过程(带税求和和不带税求和)
-- Name: ordertotal
-- Parameters: onumber = oreder number
--                       taxable = 0 if not taxable, 1 if taxable
--             ototal = order total variable

CREATE PROCEDURE ordertotalsmart ( IN onumber INT, IN taxable BOOLEAN, OUT ototal DECIMAL ( 8, 2 ) ) COMMENT 'Obtain order, 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;

# 调用上面的存储过程
CALL ordertotalsmart(20005, 0, @total);
SELECT @total;
CALL ordertotalsmart(20005, 1, @total);
SELECT @total;

# 显示创建存储过程的语句
SHOW CREATE PROCEDURE ordertotalsmart;

# 显示所有存储过程的状态
SHOW PROCEDURE STATUS;

# 显示筛选后的存储过程的状态
SHOW PROCEDURE STATUS LIKE 'ordertotalsmart';

第24章 使用游标

-- 使用游标涉及几个明确的步骤
--  在能够使用游标前,必须声明(定义)它。这个过程实际上没有
--  检索数据,它只是定义要使用的 SELECT 语句。
-- 一旦声明后,必须打开游标以供使用。这个过程用前面定义的
--  SELECT 语句把数据实际检索出来。
-- 对于填有数据的游标,根据需要取出(检索)各行。
-- 在结束游标使用时,必须关闭游标


# 创建游标(存储过程处理完成后,游标就消失(因为它局限于存储过程))
CREATE PROCEDURE processorders()
BEGIN
    DECLARE ordernumbers CURSOR
    FOR
    SELECT order_num FROM ordres;
    
    -- 打开游标
    OPEN ordernumbers;
    
    
    -- 关闭游标 
    CLOSE ordernumbers;
    
END;

# 使用游标(FETCH)
CREATE PROCEDURE processorders1()
BEGIN
    
    -- Declare local variables
    DEClARE o INT;

    -- Declare the cursor
    DECLARE ordernumbers CURSOR
    FOR
    SELECT order_num FROM orders;
    
    -- open cursor
    OPEN ordernumbers;
    
    
    -- Get order number
    FETCH ordernumbers INTO o;
    
    
    -- close cursor
    CLOSE ordernumbers;
    
    
END;


# 用游标循环获取行
CREATE PROCEDURE processorders2 ()
BEGIN
    -- Declare local variables
    -- 变量要申明在游标或者句柄之前
    DECLARE done BOOLEAN DEFAULT 0;
    DECLARE o INT;
    
    -- Declare the cursor
    DECLARE ordernumbers CURSOR
    FOR 
    SELECT order_num FROM orders;
    
    -- Declare continue handler
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
    
    -- open cursor
    OPEN ordernumbers;
    
    -- loop through all rows
    REPEAT
        
        -- Get order number
        FETCH ordernumbers INTO o;
    
    -- End of loop
    UNTIL done END REPEAT;
    
    -- close cursor
    CLOSE ordernumbers;
    
END;


# 实例
CREATE PROCEDURE porcessoredres4()
BEGIN

    -- Declare loca variables
    DECLARE done BOOLEAN DEFAULT 0;
    DECLARE o INT;
    DECLARE t DECIMAL(8,2);
    
    -- Declare the cursor
    DECLARE ordernumbers CURSOR
    FOR
    SELECT order_num FROM orders;
    
    -- Declare continue handler
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
    
    -- Create a table to store the results
    CREATE TABLE IF NOT EXISTS ordertotals (order_num INT, total DECIMAL(8,2));
    
    -- Open cursor
    OPEN ordernumbers;
    
    -- Loop through all rows
    REPEAT
        
        -- Get order number
        FETCH ordernumbers INTO o;
        
        -- Get the total for this order
        CALL ordertotalsmart(o, 1, t);
        
        -- Insert order and total into ordertotals
        INSERT INTO ordertotals(order_num, total) VALUES (o, t);
    
        -- End of loop
        UNTIL done END REPEAT;
    
        -- Close cursor
        ClOSE ordernumbers;

END;


# 调用实例
CALL porcessoredres4();

第25章 使用触发器

-- 触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。
-- 因此,每个表最多支持6个触发器(每条 INSERT 、 UPDATE和 DELETE 的之前和之后)
-- 只有表才支持触发器,视图不支持(临时表也不支持


# 创建一个触发器
CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW
BEGIN

END;


# 删除一个触发器
DROP TRIGGER newproduct;


# 创建一个触发器
CREATE TRIGGER neworder AFTER INSERT ON orders
FOR EACH ROW 
BEGIN
    
END;


# DELETE触发器
CREATE TRIGGER deleteorder BEFORE DELETE ON orders
FOR EACH ROW
BEGIN
    INSERT INTO archive_orders(order_num, ordre_date, cust_id)
    VALUES(OLD.order_num, OLD.order_date, OLD.cust_id);
END;


# UPDATE触发器
CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors
FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);

第26章 管理事务处理

# 事务 使用ROLLBACK
SELECT * FROM ordertotals;
START TRANSACTION;              
DELETE FROM ordertotals;
SELECT * FROM ordertotals;
ROLLBACK;
SELECT * FROM ordertotals;


# 使用COMMIT提交事务
START TRANSACTION;
DELETE FROM orderitems WHERE order_num = 20009;
DELETE FROM orders WHERE order_num = 20010;
COMMIT;


# 设置保留点并回滚到保留点
START TRANSACTION;
SELECT * FROM ordertotals;
SAVEPOINT delete1;
DELETE FROM ordertotals;
SELECT * FROM ordertotals;
ROLLBACK TO delete1;
SELECT * FROM ordertotals;


# 取消MYSQL的自动提交(MYSQL默认每条语句是自动提交的)
# autocommit 标志是针对每个连接而不是服务器的
SET autocommit=0;

第27章 全球化和本地化

# 查看支持的字符集
SHOW CHARACTER SET;


# 查看校对表
SHOW COLLATION;

# 查看所使用的字符集和校对
SHOW VARIABLES LIKE 'character%';
SHOW VARIABLES LIKE 'collation%';


# 创建表时指定字符集
CREATE TABLE mytable (
    columnn1 INT,
    columnn2 VARCHAR(10)
) DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;


# 对指定的列设置字符集
CREATE TABLE mytable1(
    columnn1 INT,
    columnn2 VARCHAR(10),
    columnn3 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci
) DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;


# 在检索的时候指定校对
SELECT * FROM customers
ORDER BY lastname, firstname COLLATE latin1_general_cs;

第28章 安全管理

# 查看此MYSQL服务器上的所有用户
USE mysql;
USE mysql_need_know;
SELECT `user` FROM user;
SELECT * FROM user;

# 创建一个新的用户账号并指定密码(没有任何权限,要在之后分配权限)
CREATE USER bean IDENTIFIED BY '123456';

# 重命令用户
RENAME USER bean TO bforta;

# 删除一个用户(Mysql5.0之前只会删除账号,不会删除此账号的权限需要先用 REVOKE删除与账号相关的权限)
DROP USER bean;

# 查看用户权限
SHOW GRANTS FOR bforta;
SHOW GRANTS FOR root@localhost;

-- 用户定义为 user@host MySQL的权限用用户名和主机名结
-- 合定义。如果不指定主机名,则使用默认的主机名 % (授予用
-- 户访问权限而不管主机名

# 设置权限(bforta可以检索数据库crashcourse中的所有表)
GRANT SELECT ON crashcourse.* TO bforta;

# 移除权限
REVOKE SELECT ON crashcourse.* FROM bforta;

-- GRANT 和 REVOKE 可在几个层次上控制访问权限:
--  整个服务器,使用 GRANT ALL 和 REVOKE ALL;
--  整个数据库,使用 ON database.*;
--  特定的表,使用 ON database.table;
--  特定的列;
--  特定的存储过程


-- 未来的授权 在使用 GRANT 和 REVOKE 时,用户账号必须存在,
-- 但对所涉及的对象没有这个要求。这允许管理员在创建数据库
-- 和表之前设计和实现安全措施。
-- 这样做的副作用是,当某个数据库或表被删除时(用 DROP 语
-- 句),相关的访问权限仍然存在。而且,如果将来重新创建该
-- 数据库或表,这些权限仍然起作用


# 一次授予多个权限
GRANT SELECT, INSERT ON crashcourse.* TO bforta;


# 更改指定用户的密码(使用Password函数)
SET PASSWORD FOR bforta = Password('12345');

# 更改当前登陆用户的密码
SET PASSWORD = Password('123456');

第29章 数据库维护

# 使用在命令行工具中使用mysqldump备份所有数据库到外部文件中

-- 备份:mysqldump -u root -p --databases 数据库1 数据库2 > xxx.sql
-- 还原:MySQL -uroot -p123456 <f:\all.sql
-- 常见选项:
-- --all-databases, -A: 备份所有数据库
-- --databases, -B: 用于备份多个数据库,如果没有该选项,mysqldump把第一个名字参数作为数据库名,后面的作为表名。使用该选项,mysqldum把每个名字都当作为数据库名。
-- 
-- --force, -f:即使发现sql错误,仍然继续备份
-- --host=host_name, -h host_name:备份主机名,默认为localhost
-- --no-data, -d:只导出表结构
-- --password[=password], -p[password]:密码
-- --port=port_num, -P port_num:制定TCP/IP连接时的端口号
-- --quick, -q:快速导出
-- --tables:覆盖 --databases or -B选项,后面所跟参数被视作表名
-- --user=user_name, -u user_name:用户名
-- --xml, -X:导出为xml文件
-- 1.备份全部数据库的数据和结构
-- 
-- mysqldump -uroot -p123456 -A >F:\all.sql
-- 
-- 2.备份全部数据库的结构(加 -d 参数)
-- 
-- mysqldump -uroot -p123456 -A-d>F:\all_struct.sql
-- 1.还原全部数据库:
-- 
-- (1) mysql命令行:mysql>source f:\all.sql
-- 
-- (2) 系统命令行: mysql -uroot -p123456 <f:\all.sql


# 检查表键
ANALYZE TABLE orders;

# 检查多表键
CHECK TABLE orders, orderitems;

第30章 改善性能

-- 首先,MySQL(与所有DBMS一样)具有特定的硬件建议。在学
-- 习和研究MySQL时,使用任何旧的计算机作为服务器都可以。但
-- 对用于生产的服务器来说,应该坚持遵循这些硬件建议。
--  一般来说,关键的生产DBMS应该运行在自己的专用服务器上。
--  MySQL是用一系列的默认设置预先配置的,从这些设置开始通常
-- 是很好的。但过一段时间后你可能需要调整内存分配、缓冲区大
-- 小等。(为查看当前设置,可使用 SHOW VARIABLES; 和 SHOW
-- STATUS; 。)
--  MySQL一个多用户多线程的DBMS,换言之,它经常同时执行多
-- 个任务。如果这些任务中的某一个执行缓慢,则所有请求都会执
-- 行缓慢。如果你遇到显著的性能不良,可使用 SHOW PROCESSLIST
-- 显示所有活动进程(以及它们的线程ID和执行时间)。你还可以用
-- KILL 命令终结某个特定的进程(使用这个命令需要作为管理员登
-- 录)。
--  总是有不止一种方法编写同一条 SELECT 语句。应该试验联结、并、
-- 子查询等,找出最佳的方法。
--  使用 EXPLAIN 语句让MySQL解释它将如何执行一条 SELECT 语句。
--  一般来说,存储过程执行得比一条一条地执行其中的各条MySQL
-- 语句快。
--  应该总是使用正确的数据类型。
--  决不要检索比需求还要多的数据。换言之,不要用 SELECT * (除
-- 非你真正需要每个列)。
--  有的操作(包括 INSERT )支持一个可选的 DELAYED 关键字,如果
-- 使用它,将把控制立即返回给调用程序,并且一旦有可能就实际
-- 执行该操作。
--  在导入数据时,应该关闭自动提交。你可能还想删除索引(包括
-- FULLTEXT 索引),然后在导入完成后再重建它们。
--  必须索引数据库表以改善数据检索的性能。确定索引什么不是一
-- 件微不足道的任务,需要分析使用的 SELECT 语句以找出重复的
-- WHERE 和 ORDER BY 子句。如果一个简单的 WHERE 子句返回结果所花
-- 的时间太长,则可以断定其中使用的列(或几个列)就是需要索
-- 引的对象。
--  你的 SELECT 语句中有一系列复杂的 OR 条件吗?通过使用多条
-- SELECT 语句和连接它们的 UNION 语句,你能看到极大的性能改
-- 进。
--  索引改善数据检索的性能,但损害数据插入、删除和更新的性能。
-- 如果你有一些表,它们收集数据且不经常被搜索,则在有必要之
-- 前不要索引它们。(索引可根据需要添加和删除。)
--  LIKE 很慢。一般来说,最好是使用 FULLTEXT 而不是 LIKE 。
--  数据库是不断变化的实体。一组优化良好的表一会儿后可能就面
-- 目全非了。由于表的使用和内容的更改,理想的优化和配置也会
-- 改变。
--  最重要的规则就是,每条规则在某些条件下都会被打破

附录A MySQL入门 附录B 样例表 附录C MySQL语句的语法 附录D MySQL数据类型 附录E MySQL保留字 索引

《MySQL必知必会》SQL文件:

表的创建和外键绑定:

# 在Mysql中取消外键约束 
SET FOREIGN_KEY_CHECKS=0;  
DROP TABLE customers;
DROP TABLE orderitems;
DROP TABLE orders;
DROP TABLE products;
DROP TABLE vendors;
DROP TABLE productnotes;
# 然后再设置外键约束
SET FOREIGN_KEY_CHECKS=1;  

CREATE TABLE customers
(
  cust_id      int       NOT NULL AUTO_INCREMENT COMMENT '唯一的顾客ID',
  cust_name    char(50)  NOT NULL COMMENT '顾客名',
  cust_address char(50)  NULL COMMENT '顾客的地址',
  cust_city    char(50)  NULL COMMENT '顾客的城市',
  cust_state   char(5)   NULL COMMENT '顾客的州',
  cust_zip     char(10)  NULL COMMENT '顾客的邮政编码',
  cust_country char(50)  NULL COMMENT '顾客的国家',
  cust_contact char(50)  NULL COMMENT '顾客的联系名',
  cust_email   char(255) NULL COMMENT '顾客的联系email地址',
  PRIMARY KEY (cust_id)
) ENGINE=InnoDB;
CREATE TABLE orderitems
(
  order_num  int          NOT NULL COMMENT '订单号',
  order_item int          NOT NULL COMMENT '订单物品号',
  prod_id    char(10)     NOT NULL COMMENT '产品ID',
  quantity   int          NOT NULL COMMENT '物品数量',
  item_price decimal(8,2) NOT NULL COMMENT '物品价格',
  PRIMARY KEY (order_num, order_item)
) ENGINE=InnoDB;
CREATE TABLE orders
(
  order_num  int      NOT NULL AUTO_INCREMENT COMMENT '唯一订单号',
  order_date datetime NOT NULL COMMENT '订单日期',
  cust_id    int      NOT NULL COMMENT '订单顾客ID',
  PRIMARY KEY (order_num)
) ENGINE=InnoDB;
CREATE TABLE products
(
  prod_id    char(10)      NOT NULL COMMENT '唯一的产品ID',
  vend_id    int           NOT NULL COMMENT '产品供应商ID',
  prod_name  char(255)     NOT NULL COMMENT '产品名',
  prod_price decimal(8,2)  NOT NULL COMMENT '产品价格',
  prod_desc  text          NULL COMMENT '产品描述',
  PRIMARY KEY(prod_id)
) ENGINE=InnoDB;
CREATE TABLE vendors
(
  vend_id      int      NOT NULL AUTO_INCREMENT COMMENT '唯一的供应商ID',
  vend_name    char(50) NOT NULL COMMENT '供应商名',
  vend_address char(50) NULL COMMENT '供应商的地址',
  vend_city    char(50) NULL COMMENT '供应商的城市',
  vend_state   char(5)  NULL COMMENT '供应商的州',
  vend_zip     char(10) NULL COMMENT '供应商的邮政编码',
  vend_country char(50) NULL COMMENT '供应商的国家',
  PRIMARY KEY (vend_id)
) ENGINE=InnoDB;
CREATE TABLE productnotes
(
  note_id    int           NOT NULL AUTO_INCREMENT COMMENT '唯一注释ID',
  prod_id    char(10)      NOT NULL COMMENT '产品ID',
  note_date datetime       NOT NULL COMMENT '增加注释的日期',
  note_text  text          NULL COMMENT '注释文本',
  PRIMARY KEY(note_id),
  FULLTEXT(note_text)
) ENGINE=MyISAM;
ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num) REFERENCES orders (order_num);
ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_products FOREIGN KEY (prod_id) REFERENCES products (prod_id);
ALTER TABLE orders ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id) REFERENCES customers (cust_id);
ALTER TABLE products ADD CONSTRAINT fk_products_vendors FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);

##########################
# Populate customers table
##########################
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');


########################
# Populate vendors table
########################
INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES(1001,'Anvils R Us','123 Main Street','Southfield','MI','48075', 'USA');
INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES(1002,'LT Supplies','500 Park Street','Anytown','OH','44333', 'USA');
INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES(1003,'ACME','555 High Street','Los Angeles','CA','90046', 'USA');
INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES(1004,'Furball Inc.','1000 5th Avenue','New York','NY','11111', 'USA');
INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES(1005,'Jet Set','42 Galaxy Road','London', NULL,'N16 6PS', 'England');
INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES(1006,'Jouets Et Ours','1 Rue Amusement','Paris', NULL,'45678', 'France');


#########################
# Populate products table
#########################
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('ANV01', 1001, '.5 ton anvil', 5.99, '.5 ton anvil, black, complete with handy hook');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('ANV02', 1001, '1 ton anvil', 9.99, '1 ton anvil, black, complete with handy hook and carrying case');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('ANV03', 1001, '2 ton anvil', 14.99, '2 ton anvil, black, complete with handy hook and carrying case');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('OL1', 1002, 'Oil can', 8.99, 'Oil can, red');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('FU1', 1002, 'Fuses', 3.42, '1 dozen, extra long');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('SLING', 1003, 'Sling', 4.49, 'Sling, one size fits all');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('TNT1', 1003, 'TNT (1 stick)', 2.50, 'TNT, red, single stick');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('TNT2', 1003, 'TNT (5 sticks)', 10, 'TNT, red, pack of 10 sticks');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('FB', 1003, 'Bird seed', 10, 'Large bag (suitable for road runners)');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('FC', 1003, 'Carrots', 2.50, 'Carrots (rabbit hunting season only)');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('SAFE', 1003, 'Safe', 50, 'Safe with combination lock');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('DTNTR', 1003, 'Detonator', 13, 'Detonator (plunger powered), fuses not included');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('JP1000', 1005, 'JetPack 1000', 35, 'JetPack 1000, intended for single use');
INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('JP2000', 1005, 'JetPack 2000', 55, 'JetPack 2000, multi-use');



#######################
# Populate orders table
#######################
INSERT INTO orders(order_num, order_date, cust_id)
VALUES(20005, '2005-09-01', 10001);
INSERT INTO orders(order_num, order_date, cust_id)
VALUES(20006, '2005-09-12', 10003);
INSERT INTO orders(order_num, order_date, cust_id)
VALUES(20007, '2005-09-30', 10004);
INSERT INTO orders(order_num, order_date, cust_id)
VALUES(20008, '2005-10-03', 10005);
INSERT INTO orders(order_num, order_date, cust_id)
VALUES(20009, '2005-10-08', 10001);


###########################
# Populate orderitems table
###########################
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20005, 1, 'ANV01', 10, 5.99);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20005, 2, 'ANV02', 3, 9.99);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20005, 3, 'TNT2', 5, 10);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20005, 4, 'FB', 1, 10);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20006, 1, 'JP2000', 1, 55);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20007, 1, 'TNT2', 100, 10);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20008, 1, 'FC', 50, 2.50);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 1, 'FB', 1, 10);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 2, 'OL1', 1, 8.99);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 3, 'SLING', 1, 4.49);
INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 4, 'ANV03', 1, 14.99);

#############################
# Populate productnotes table
#############################
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(101, 'TNT2', '2005-08-17',
'Customer complaint:
Sticks not individually wrapped, too easy to mistakenly detonate all at once.
Recommend individual wrapping.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(102, 'OL1', '2005-08-18',
'Can shipped full, refills not available.
Need to order new can if refill needed.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(103, 'SAFE', '2005-08-18',
'Safe is combination locked, combination not provided with safe.
This is rarely a problem as safes are typically blown up or dropped by customers.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(104, 'FC', '2005-08-19',
'Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(105, 'TNT2', '2005-08-20',
'Included fuses are short and have been known to detonate too quickly for some customers.
Longer fuses are available (item FU1) and should be recommended.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(106, 'TNT2', '2005-08-22',
'Matches not included, recommend purchase of matches or detonator (item DTNTR).'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(107, 'SAFE', '2005-08-23',
'Please note that no returns will be accepted if safe opened using explosives.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(108, 'ANV01', '2005-08-25',
'Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(109, 'ANV03', '2005-09-01',
'Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(110, 'FC', '2005-09-01',
'Customer complaint: rabbit has been able to detect trap, food apparently less effective now.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(111, 'SLING', '2005-09-02',
'Shipped unassembled, requires common tools (including oversized hammer).'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(112, 'SAFE', '2005-09-02',
'Customer complaint:
Circular hole in safe floor can apparently be easily cut with handsaw.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(113, 'ANV01', '2005-09-05',
'Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.'
);
INSERT INTO productnotes(note_id, prod_id, note_date, note_text)
VALUES(114, 'SAFE', '2005-09-07',
'Call from individual trapped in safe plummeting to the ground, suggests an escape hatch be added.
Comment forwarded to vendor.'
);


3.类似Oracle中的经典SQL练习案例

/*
Navicat MySQL Data Transfer

Source Server         : MySQL_Localhost
Source Server Version : 50540
Source Host           : localhost:3306
Source Database       : like_oracle

Target Server Type    : MYSQL
Target Server Version : 50540
File Encoding         : 65001

Date: 2020-05-05 14:06:37
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for bonus
-- ----------------------------
DROP TABLE IF EXISTS `bonus`;
CREATE TABLE `bonus` (
  `ename` varchar(10) DEFAULT NULL,
  `job` varchar(9) DEFAULT NULL,
  `sal` int(11) DEFAULT NULL,
  `comm` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of bonus
-- ----------------------------

-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
  `deptno` int(2) NOT NULL,
  `dname` varchar(14) DEFAULT NULL,
  `loc` varchar(13) DEFAULT NULL,
  PRIMARY KEY (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES ('10', 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES ('20', 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES ('30', 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES ('40', 'OPERATIONS', 'BOSTON');

-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `empno` int(4) NOT NULL,
  `ename` varchar(10) DEFAULT NULL,
  `job` varchar(9) DEFAULT NULL,
  `mgr` int(4) DEFAULT NULL,
  `hiredate` date DEFAULT NULL,
  `sal` float(7,2) DEFAULT NULL,
  `comm` float(7,2) DEFAULT NULL,
  `deptno` int(2) DEFAULT NULL,
  PRIMARY KEY (`empno`),
  KEY `fk_deptno` (`deptno`),
  CONSTRAINT `fk_deptno` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800.00', null, '20');
INSERT INTO `emp` VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600.00', '300.00', '30');
INSERT INTO `emp` VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250.00', '500.00', '30');
INSERT INTO `emp` VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975.00', null, '20');
INSERT INTO `emp` VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250.00', '1400.00', '30');
INSERT INTO `emp` VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850.00', null, '30');
INSERT INTO `emp` VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450.00', null, '10');
INSERT INTO `emp` VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-07-13', '3000.00', null, '20');
INSERT INTO `emp` VALUES ('7839', 'KING', 'PRESIDENT', null, '1981-11-07', '5000.00', null, '10');
INSERT INTO `emp` VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500.00', '0.00', '30');
INSERT INTO `emp` VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-07-13', '1100.00', null, '20');
INSERT INTO `emp` VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950.00', null, '30');
INSERT INTO `emp` VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000.00', null, '20');
INSERT INTO `emp` VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300.00', null, '10');

-- ----------------------------
-- Table structure for salgrade
-- ----------------------------
DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (
  `grade` int(11) DEFAULT NULL,
  `losal` int(11) DEFAULT NULL,
  `hisal` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of salgrade
-- ----------------------------
INSERT INTO `salgrade` VALUES ('1', '700', '1200');
INSERT INTO `salgrade` VALUES ('2', '1201', '1400');
INSERT INTO `salgrade` VALUES ('3', '1401', '2000');
INSERT INTO `salgrade` VALUES ('4', '2001', '3000');
INSERT INTO `salgrade` VALUES ('5', '3001', '9999');

posted @ 2020-03-22 21:46  wqkeep  阅读(887)  评论(0编辑  收藏  举报