文章目录

  • 附录 语法总结
    • DQL(数据库查询语句)
    • DML(数据库操作语句)
    • DDL(数据库定义语句)
    • DCL(数据库控制语句)
  • 附录 数据库脚本
  • 1 了解SQL
  • 2 mysql简介
  • 3 使用MySQL
  • 4 检索数据
  • 5 排序检索数据
  • 6 过滤数据
  • 7 数据过滤
  • 8 用通配符的技巧
  • 9 用正则表达式进行搜索
  • 10 创建计算字段
  • 11 使用数据处理函数
  • 12 汇总数据
  • 13 分组数据
  • 14 使用子查询
  • 15 联结表
  • 16 高级联结
  • 17 组合查询
  • 18 全文本搜索
  • 19 插入数据
  • 20 更新和删除数据
  • 21 创建和操作数据库表
  • 22 使用视图
  • 23 使用存储过程
  • 24 使用游标
  • 25 触发器
  • 26 管理事务处理
  • 27 全球化和本地化
  • 28 安全管理
  • 29 数据库维护
  • 30 改善性能

附录 语法总结

DQL(数据库查询语句)

# select
select columnname,...
fromtablename,...
[where...]
[union...]
[group by...]
[having...]
[order by...]

DML(数据库操作语句)

# insert
insert into table_name [(columns,...)] values [(values,...)];# insert select
insert into table_name1 [(columns,...)] select columns,... form table_name2,... [where]# update:更新表中一行或者多行
update table_name
set columnname= value,...
[where...]# delete:删除一行或者多行
delete from table_name [where ...];# drop
drop dateabase|index|procedure|table|trigger|user|view item_name;

DDL(数据库定义语句)

# create user
create user user_name[@hostname]
[identified by [password] 'user_password']# alter table:更新已存在表的模式
alter table table_name(add column datatype [null|not null] [constraints],change column columns datatype [null|not null] [constraints],drop column
)# create table table_name(column datetype [null||not null] [constraints],column datetype [null||not null] [constraints],... # 最后不能有逗号
);# create index
create index index_name on table_name(column [asc|desc],...)# create view
create [on replace] view view_name
as
select ...;# create procedure
create procedure precedure_name([parameters])
begin
...
end;

DCL(数据库控制语句)

# start transaction:开启一个事务块
start transaction;# commit
commit;# rollback:撤销一个事务块
rollback [to savepointname];# save point:为rollback设置保留点
savepoint spl;  # 授权

附录 数据库脚本

  • 备注:《mysql必知必会》读书笔记

  • 本书的数据库脚本:mysql必知必会官网

########################################
# MySQL Crash Course
# http://www.forta.com/books/0672327120/
# Example table creation scripts
################################################################
# Create customers table
########################
CREATE TABLE customers
(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;#########################
# Create orderitems table
#########################
CREATE TABLE orderitems
(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;#####################
# Create orders table
#####################
CREATE TABLE orders
(order_num  int      NOT NULL AUTO_INCREMENT,order_date datetime NOT NULL ,cust_id    int      NOT NULL ,PRIMARY KEY (order_num)
) ENGINE=InnoDB;#######################
# Create products table
#######################
CREATE TABLE products
(prod_id    char(10)      NOT NULL,vend_id    int           NOT NULL ,prod_name  char(255)     NOT NULL ,prod_price decimal(8,2)  NOT NULL ,prod_desc  text          NULL ,PRIMARY KEY(prod_id)
) ENGINE=InnoDB;######################
# Create vendors table
######################
CREATE TABLE vendors
(vend_id      int      NOT NULL AUTO_INCREMENT,vend_name    char(50) NOT NULL ,vend_address char(50) NULL ,vend_city    char(50) NULL ,vend_state   char(5)  NULL ,vend_zip     char(10) NULL ,vend_country char(50) NULL ,PRIMARY KEY (vend_id)
) ENGINE=InnoDB;###########################
# Create productnotes table
###########################
CREATE TABLE productnotes
(note_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;#####################
# Define foreign keys
#####################
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);
########################################
# MySQL Crash Course
# http://www.forta.com/books/0672327120/
# Example table population scripts
##################################################################
# 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.'
);

1 了解SQL

  • 数据库:保存有组织的数据的容器(通常是一个文件或者一组文件)

    • 数据库软件(DBMS):人们通常使用的是数据库软件,数据库是通过DBMS创建和操纵的容器
  • 表:某种特定类型数据的结构化清单
    • 模式:关于数据库和表的布局及特性的信息
    • 列:表中的一个字段,所有表都是由一个或多个列组成的。
    • 行:表中的一个记录
  • 主键:表中每一行都应该有可以唯一标识自己的一列,其值可以唯一区分表中的每个行。没有主键,更新或者删除表中特定的行很困难,因为没有安全的方法保证只涉及相关的行。
  • Mysql主键规则:
    • 任意两行都不具有相同的主键值
    • 每个行都必须具有一个主键值,主键值不允许为null
# 添加主键
alter table t add column t.id int primary key auto_increment;

2 mysql简介

  • 简单介绍一下Mysql,自行查询相关资料即可

3 使用MySQL

# 展示所有数据库
show databases;# 创建数据库
create database learn_mysql;# 使用数据库
use learn_mysql;# 展示该数据库下所有的表
show tables;# 查看表结构:展示某个表中所有列的设计信息,与describe table_name等价
show columns from customers;# 与上面等价,简化书写
describe customers;

4 检索数据

重点:学习limit

# select默认查询出来的数据是无序的
SELECTprod_name
FROMproducts;# 查询和去重查询
SELECTvend_id
FROMproducts;SELECT DISTINCT vend_id
FROMproducts;# limit,数据库行数是从0开始的:行0,行1,行2...
# llimit (0,1) = 第一个数为开始为位置(行0),第二个数为检索的行数
# rowIndex = (前端页数-1)*每页展示数量
SELECTprod_name
FROMproducts
LIMIT 0,1;

5 排序检索数据

  • order by :默认是升序,desc改成降序;可以加limit找出最值
# 单个列排列:order by,默认是升序排列
SELECTprod_name
FROMproducts
ORDER BYprod_name;# 多个列排列:prod_price相同,prod_name才进行组内排序;prod_price都不相同,prod_name就不会排序
SELECTprod_price,prod_name
FROMproducts
ORDER BYprod_price,prod_name;# desc 降序排序
SELECTprod_id,prod_price,prod_name
FROMproducts
ORDER BYprod_price DESC;# 前一个降序,后一个升序
SELECTprod_id,prod_price,prod_name
FROMproducts
ORDER BYprod_price DESC,prod_name;# 找出最高价格
SELECTprod_price
FROMproducts
ORDER BYprod_price DESC LIMIT 1;

6 过滤数据

操作符 说明
= 等于
<> 不等于
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
between 两者之间
# where:不区分大小写
SELECTprod_name,prod_price
FROMproducts
WHEREprod_name = 'fuses';SELECTprod_name,prod_price
FROMproducts
WHEREprod_name = 'FUses';# 不等于的两种写法
SELECTvend_id,prod_name
FROMproducts
WHEREvend_id <> 1003;SELECTvend_id,prod_name
FROMproducts
WHEREvend_id != 1003;# 范围查找:between + and
SELECTprod_name,prod_price
FROMproducts
WHEREprod_price BETWEEN 5 AND 10;# 区分:1.in是匹配准确的值 2.between是匹配范围内的值,两者完全不相同
SELECTprod_name,prod_price
FROMproducts
WHEREprod_price IN ( 5, 6 );# 空值查询:is null
SELECTcust_id
FROMcustomers
WHEREcust_email IS NULL;

7 数据过滤

in 运算符优点:

  1. 语法更清楚和直观
  2. 计算次序更容易管理
  3. in 比 or 计算速度更快
  4. in 最大优点是可以包含其他select 语句
# where+and:两者都要匹配
SELECTprod_id,prod_price,prod_name
FROMproducts
WHEREvend_id = 1003 AND prod_price <= 10;# where+or:匹配任何一个都可以
SELECTprod_name,prod_price
FROMproducts
WHEREvend_id = 1002 OR vend_id = 1003;# and+or:and的优先级比or高,vend_id=1003 and prod_price >=10先执行
SELECTprod_name,prod_price
FROMproducts
WHEREvend_id = 1002 OR vend_id = 1003 AND prod_price >= 10;# or字句需要先执行的话,需要加括号
SELECTprod_name,prod_price
FROMproducts
WHERE( vend_id = 1002 OR vend_id = 1003 ) AND prod_price >= 10;# in:in (a,b) 等价 a or b
SELECTprod_name,prod_price
FROMproducts
WHEREvend_id IN ( 1002, 1003 )
ORDER BYprod_name;
SELECTprod_name,prod_price
FROMproducts
WHEREvend_id = 1002 OR vend_id = 1003
ORDER BYprod_name;# not + in :mysql支持对in、between、exists句子使用
SELECTprod_name,prod_price
FROMproducts
WHEREvend_id NOT IN ( 1002, 1003 )
ORDER BYprod_name;

8 用通配符的技巧

# 通配符%:默认是不区分大小写不能匹配null;如果是'%anvil'不能匹配最后有空格的情况,'%anvil%'才行
SELECTprod_id,prod_name
FROMproducts
WHEREprod_name LIKE 'Jet%';SELECTprod_id,prod_name
FROMproducts
WHEREprod_name LIKE 'jet%';# 通配符%前后都使用:
SELECTprod_id,prod_name
FROMproducts
WHEREprod_name LIKE '%anvil%';# 通配符_:只匹配单个字符,所有.5 ton anvil就匹配不出来,%才行
SELECTprod_id,prod_name
FROMproducts
WHEREprod_name LIKE '_ ton anvil';
SELECTprod_id,prod_name
FROMproducts
WHEREprod_name LIKE '%ton anvil';

9 用正则表达式进行搜索

空白元字符 说明
\\f 换页
\\n 换行
\\r 回车
\\t 制表
\\v 纵向制表
字符类 说明
[:alnum:] 任意字母或数字(同[a-zA-Z0-9])
[:alpha:] 任意字符(同[a-zA-Z])
[:blank:] 空格和制表(同[\\t])
[:cntrl:] ASCII控制字符(ASCII0到32和127)
[:digit:] 任意数字(同[0-9])
[:graph:] 与[:print:]相同,但不包含空格
[:lower:] 任意小写字母(同[a-z])
[:prinit:] 任意可打印字符
[: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)
定位元字符 说明
^ 文本的开始
$ 文本的结束
[[:<:]] 词的开始
[[:>:]] 词的结尾
# regexp:表示使用正则表达式,'1000'等价于%1000%,相当于模糊匹配
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '1000';SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '.000';# like和regexp的区别
SELECTprod_name
FROMproducts
WHEREprod_name LIKE '1000';# like匹配整个列,被匹配文本在列值中出现,相应的行也不会被返回
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '1000';# regexo匹配整个列,被匹配文本在列值中出现,相应的行会被返回
# regexp:默认是不去区分大小写,如果需要区分大小写,regexp binary
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP BINARY 'JetPack .000';# regexp+|:与or功能类似
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '1000|2000'
ORDER BYprod_name;# []:表示匹配特定的某个字符
# [123] ton = 严格按照[1|2|3] ton
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '[123] ton'
ORDER BYprod_name;# ^:取反
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '[^123] ton'
ORDER BYprod_name;# 1|2|3 ton:列里包含1或者2或者3 ton,与[123 ton]含义区分开
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '1|2|3 ton'
ORDER BYprod_name;# [1-5]:表示范围
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '[1-5] ton'
ORDER BYprod_name;# .表示匹配任意字符,
SELECTvend_name
FROMvendors
WHEREvend_name REGEXP '.'
ORDER BYvend_name;# 匹配特殊字符加//,//.才是匹配.字符
SELECTvend_name
FROMvendors
WHEREvend_name REGEXP '\\.'
ORDER BYvend_name;# 匹配(数字 stick)或者(数字 sticks)
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '\\([0-9] sticks?\\)'
ORDER BYprod_name;
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '\\([:digit:] sticks?\\)'
ORDER BYprod_name;# 匹配包含4个数字
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '[:digit:]{4}'
ORDER BYprod_name;# 定位符:^在正则表达式表示从文本的开始
# 匹配以一个数或者小数点开始的所有产品
SELECTprod_name
FROMproducts
WHEREprod_name REGEXP '^[0-9\\.]'
ORDER BYprod_name;

10 创建计算字段

  • 字段:基本上与列意思相同,但是列名是数据库实际存储的列的名字,而字段通常是经过用在计算字段的连接上

    • 拼接(concatenate):将值拼接到一起构成单个值
# CONCAT使用拼接,mysql的拼接是使用concat,别的sql会有区别
SELECTCONCAT( vend_name, ' (', vend_country, ')' )
FROMvendors
ORDER BYvend_name;# Rtrim:去掉右边的空格
SELECTCONCAT( Rtrim( vend_name ), ' (', Rtrim( vend_country ), ')' )
FROMvendors
ORDER BYvend_name;# 取别名
SELECTCONCAT( Rtrim( vend_name ), ' (', Rtrim( vend_country ), ')' ) AS vend_title
FROMvendors
ORDER BYvend_name;# 执行计算,mysql算术运算符支持+,-,*,/四种
SELECTprod_id,quantity,item_price
FROMorderitems
WHEREorder_num = 20005;
SELECTprod_id,quantity,item_price,quantity * item_price AS expanded_price
FROMorderitems
WHEREorder_num = 20005;# mysql的select可以省略from字句便于简单地访问和处理数据
SELECT3 * 2;
# 去掉首尾的空格
SELECTtrim( ' abc ' );
# 返回当前日期和时间
SELECTNow();

11 使用数据处理函数

常用的文本处理函数 说明
Left() 返回串左边的字符
Length() 返回串的长度
Locate() 找出串的一个子串
Lower() 将串转换为小写
LTrim() 去掉串左边空格
Right() 返回串右边的字符
Rtrim() 去掉串右边的空格
Soundex() 返回串的SoundDex值
SubString() 返回子串的字符
Upper 将串转换为大写

Soundex():将任何文本串转换为描述其语言表示的字母数字模式的算法,以下举个例子

# SOUNDEX():匹配发音相似的文本
SELECTcust_name,cust_contact
FROMcustomers
WHEREcust_contact = 'Y. Lie';
SELECTcust_name,cust_contact
FROMcustomers
WHEREsoundex( cust_contact ) = soundex( 'Y. Lie' );
常用日期和时间处理函数 说明
AddDate() 添加一个日期(天、周等)
AddTime() 添加一个日期(时、分等)
CurDate() 返回当前日期
CurTime() 返回当前时间
Date() 返回日期时间的日期部分
DateDiff() 计算两个日期天数之差
Date_Add() 高度灵活的日期运算函数
Date_Format() 返回一个格式化的日期或时间串
Day() 返回一个日期的天数部分
DayOfWeek() 对于一个日期,返回对应的星期几
Hour() 返回小时部分
Minute() 返回分钟部分
Month() 返回月份部分
Now() 返回当前日期和时间
Second() 返回秒部分
Time() 返回时间部分
Year() 返回年份部分
常用数值处理函数 说明
Abs() 绝对值
Cos() 余弦
Exp() 指数值
Mod() 除操作的余数
Pi() 圆周率
Rand() 随机数
Sin() 正弦
Sqart() 平方根
Tan() 正切
# 文本处理函数:Upper
SELECTvend_name,Upper( vend_name ) AS vend_name_upcase
FROMvendors
ORDER BYvend_name;# 日期yyyy-mm-dd,时间HH:MM:SS
# 这样日期是不严谨的,只能查出时间默认为0的日期,比如2005-09-01 00:00:00
# 但是2005-09-01 10:20:30就无法查出想要的结果
SELECTcust_id,order_num
FROMorders
WHEREorder_date = '2005-09-01';# 使用Date()和Time()函数解析Datetime类型数据
SELECTcust_id,order_num
FROMorders
WHEREDate( order_date ) = '2005-09-01';
SELECTcust_id,order_num
FROMorders
WHERETime( order_date ) = '01:00:00';# 搜索2005年9月以内的订单
# 方法1:需要知道月份的具体天数
SELECTcust_id,order_num
FROMorders
WHEREDate( order_date ) BETWEEN '2005-09-01' AND '2005-09-30';# 方法2:不需要知道具体的天数,最方便
SELECTcust_id,order_num
FROMorders
WHEREYEAR ( order_date ) = '2005' AND MONTH ( order_date )= '9';

12 汇总数据

聚集函数 说明
AVG() 平均值,忽略null值
COUNT() 行数
MAX() 最大值
MIN() 最小值
SUM() 之和
# avg:算平均值
SELECTavg( prod_price ) AS avg_price
FROMproducts;# 算特定列的平均值
SELECTavg( prod_price ) AS avg_price
FROMproducts
WHEREvend_id = 1003;# 算去重后特定列的平均值
SELECTavg( DISTINCT prod_price ) AS avg_price
FROMproducts
WHEREvend_id = 1003;# count(*)和(1):算行数
# count(*):返回所有的行数,包含null数量
# count(column):返回指定数值非null的数量
SELECTcount(*) AS num_cust
FROMcustomers;
SELECTcount( 1 ) AS num_cust
FROMcustomers;
SELECTcount( cust_email ) AS num_cust
FROMcustomers;# max
SELECTmax( prod_price ) AS max_price
FROMproducts;# min
SELECTmin( prod_price ) AS max_price
FROMproducts;# sum
SELECTsum( quantity ) AS times_ordered
FROMorderitems
WHEREorder_num = 20005;# 数学运算后的sum值
# 思维:查出来的列可以进行各种算术运算,然后使用sum()等函数计算
SELECTsum( item_price * quantity ) AS total_price
FROMorderitems
WHEREorder_num = 20005;# 组合聚集函数
SELECTcount(*) AS num_items,min( prod_price ) AS min_price,max( prod_price ) AS max_price,avg( prod_price ) AS avg_price
FROMproducts;

13 分组数据

使用group by的注意事项:group by 加深理解

  • group by后面可以跟多个列,看成一个整体来进行分组,自行思考聚合的过程
  • 如果在group by字句嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算
  • select +表达式,则group by 字句中使用相同的表达式
  • select+聚集函数/group by 分组列,否则会报错
  • 如果分组列中具有null值,则null将作为一个分组返回。如果列中有多行null值,他们将分在一组
  • group by 字句必须出现在where之后,order by之前

having和where区别:

  • where在分组前进行过滤,having 在数组分组后进行过滤
order by group by
排序产生的输出 分组行。但输出可能不是分组的顺序
任意列都可以使用 只可能使用选择列或表达式列,而且必须使用每个选择列表达式
不一定需要 如果和聚集函数一起使用列(或表达式),则必须使用
字句执行顺序 说明 是否必须使用
select 要返回的列或表达式
from 从中检索数据的表 仅在从表选择数据时使用
where 行级过滤
group by 分组说明 仅在按组计算聚焦使用
having 组级过滤
order by 输出排序顺序
limit 要检索的行数
# 如果要返回每个供应商提供的产品数目怎么办?
SELECTcount( 1 )
FROMproducts
WHEREvend_id = 1003;# group by:将数组进行分组,对每个组而不是每个结果集进行了聚集
# 使用group by输出可能不是分组的原本排序,所以好习惯是group by + order  by一起使用
SELECTvend_id,count(*) AS num_prods
FROMproducts
GROUP BYvend_id
ORDER BYvend_id;# group by +  rollup:对每个分组汇总了总数(级别)
SELECTvend_id,count(*) AS num_prods
FROMproducts
GROUP BYvend_id WITH ROLLUP
ORDER BYvend_id;# gruop by是分组,+having 就是过滤聚合分组
SELECTcust_id,count(*) AS orders
FROMorders
GROUP BYcust_id
HAVINGcount(*) >= 2;# where先过滤需要的行,然后group by+having,体会执行顺序
SELECTvend_id,count(*) AS num_prods
FROMproducts
WHEREprod_price >= 10
GROUP BYvend_id
HAVINGcount(*)>= 2
ORDER BYvend_id;SELECTvend_id,count(*) AS num_prods
FROMproducts
GROUP BYvend_id
HAVINGcount(*)>= 2
ORDER BYvend_id;# 检索总计订单价格>=50的订单号和总结订单价格,使用group by + order by好习惯的由来
SELECTorder_num,sum( quantity * item_price ) AS ordertotal
FROMorderitems
GROUP BYorder_num
HAVINGsum( quantity * item_price ) >= 50;SELECTorder_num,sum( quantity * item_price ) AS ordertotal
FROMorderitems
GROUP BYorder_num
HAVINGsum( quantity * item_price ) >= 50
ORDER BYordertotal;

14 使用子查询

  • select * from table where col in(子查询)

    • 注意:子查询列个数和wherect col个数对应
# 列出订购物品TNT2的所有客户
# 1.检索包含物品TNT2的所有订单的编号
# 2.检索具有前一步列出的订单编号的所有客户ID
# 3.检索前一步返回的所有客户ID的客户信息
SELECTcust_name,cust_contact
FROMcustomers
WHEREcust_id IN ( SELECT cust_id FROM orders WHERE order_num IN ( SELECT order_num FROM orderitems WHERE prod_id = 'TNT2' ) );
  • 内表可以使用外表字段进行子查询
# customers表中每个客户的订单总数,订单和相应客户的ID存储在orders表中
# 该子查询对检索出的每个客户执行了一次,子查询执行了5次,因此检索出了5个客户
SELECTcust_name,cust_state,( SELECT count(*) FROM orders WHERE orders.cust_id = customers.cust_id ) AS orders
FROMcustomers
ORDER BYcust_name;

15 联结表

笛卡尔积:

  • 由没有联结条件的表关系返回的结构为笛卡尔积。检索出的行数目将是第一个表中的行数乘以第二个表中的行数
  • 说明:使用多表查询时候,请必须使用where搭配,否则会出现很多虚假数据
# from后跟两个表=联结两张表,有相同的列名,必须指定表名.column
SELECTvend_name,prod_name,prod_price
FROMvendors,products
# 多表连接查询时,请使用where搭配,否则会出现很多无用数据=笛卡尔积
WHEREvendors.vend_id = products.vend_id
ORDER BYvend_name,prod_name;
  • 下面与上面sql等价,推荐使用下边写法联结条件on替代上面where条件
SELECTvend_name,prod_name,prod_price
FROMvendors# 内连接:两张表交集列数据必须有,其余列可为nullINNER JOIN products ON vendors.vend_id = products.vend_id
ORDER BYvend_name,prod_name;
  • 可以联结多个表,但是联结过多性能越差
# 联结多个表
SELECTprod_name,vend_name,prod_price,quantity
FROMorderitems,products,vendors
WHEREproducts.vend_id = vendors.vend_id
AND orderitems.prod_id = products.prod_id
AND order_num = 20005;
  • 14章的订购产品TNT2的客户列表改成联结查询
# 14章的订购产品TNT2的客户列表改成联结查询
# 14章子查询
SELECTcust_name,cust_contact
FROMcustomers
WHEREcust_id IN ( SELECT cust_id FROM orders WHERE order_num IN ( SELECT order_num FROM orderitems WHERE prod_id = 'TNT2' ) );# 多表联结查询是最简单写法
SELECTcust_name,cust_contact
FROMcustomers,orders,orderitems
WHEREcustomers.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num AND prod_id = 'TNT2';

16 高级联结

  • 看到表数据,第一反应是必须有相同id下自连接的数据模型,这是许多复杂sql 的基础

SELECT*
FROMproducts AS p1,products AS p2
WHEREp1.vend_id = p2.vend_id AND p1.prod_name = '1 ton anvil'
ORDER BYp1.vend_id,p1.prod_id;
  • 学会取别名

    • 不仅作用于where字句,select列表,order by字句以及语句的其他部分
# 给列取别名
SELECTCONCAT( Rtrim( vend_name ), ' (', Rtrim( vend_country ), ')' ) AS vend_title
FROMvendors
ORDER BYvend_name;# 给表取别名
SELECTcust_name,cust_contact
FROMcustomers as c,orders as o ,orderitems as oi
WHEREc.cust_id = o.cust_id AND oi.order_num = o.order_num AND prod_id = 'TNT2';
  • 联结查询,比子查询快很多,应该习惯使用联结查询
# 找到生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品
# 子查询法,速度是最慢的,尽量少使用
SELECTprod_id,prod_name
FROMproducts
WHEREvend_id = ( SELECT vend_id FROM products WHERE prod_id = 'DTNTR' );# 自连接法,速度最快
SELECTp1.prod_id,p1.prod_name
FROMproducts AS p1,products AS p2
WHERE# 逻辑:相同供应商下,prod_id指定为xx出来p1.vend_id = p2.vend_id AND p2.prod_id = 'DTNTR';
  • 自然联结:对某个表使用通配符,其他表指定没有产生重复的列,所以不会报错

# 自然联结:通配符只对第一个表使用,所有其他列明确列出,所以没有重复的列被检索出来
SELECTc.*,o.order_num,o.order_date,oi.prod_id,oi.quantity,oi.item_price
FROMcustomers as c,orders as o ,orderitems as oi
WHEREc.cust_id = o.cust_id AND oi.order_num = o.order_num AND prod_id = 'FB';
  • 联结产生null的问题:区分inner join,left join 的区别

# inner join:只返回两张表都有的数据,不会出现null
SELECTcustomers.cust_id,orders.order_num
FROMcustomersINNER JOIN orders ON customers.cust_id = orders.cust_id;# left join:以左边表所有字段都返回,关联右边表没有的数据显示为null
SELECTcustomers.cust_id,orders.order_num
FROMcustomersLEFT JOIN orders ON customers.cust_id = orders.cust_id;
  • 内部联结和外部联结的练习:检索所有客户及每个客户所下的订单数,是使用inner join 还是lfet join呢?
# inner join内部联结
SELECTcustomers.cust_name,customers.cust_id,count( orders.order_num ) AS num_ord
FROMcustomersINNER JOIN orders ON customers.cust_id = orders.cust_id
GROUP BYcustomers.cust_id;# left outer join = left join外部联结
SELECTcustomers.cust_name,customers.cust_id,count( orders.order_num ) AS num_ord
FROMcustomersleft outer join orders ON customers.cust_id = orders.cust_id
GROUP BYcustomers.cust_id;

17 组合查询

union规则:允许将多个select查询出的结果集作为单个结果集返回

  • union必须有2条或2条以上的select语句组成,语句之间用关键字union分隔
  • 重点:union中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)
  • 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐式转换的类型
# union:可以将多个查询汇集到同一个结果集中
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREprod_price <= 5 # union连接UNION
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREvend_id IN ( 1001, 1002 );# union与where多条件查询相同
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREprod_price <= 5 OR vend_id IN ( 1001, 1002 );
# union all:重复行多次显示,不会合并
# union :默认合并重复的行
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREprod_price <= 5 # union allUNION ALL
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREvend_id IN ( 1001, 1002 );
# union排序:使用order by是针对union所以组合的表的
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREprod_price <= 5 # unionUNION
SELECTvend_id,prod_id,prod_price
FROMproducts
WHEREvend_id IN ( 1001, 1002 )
ORDER BYvend_id,prod_price;

18 全文本搜索

全文本布尔操作符 说明
+ 包含,词必须存在
- 排除,词必须不存在
> 包含,但增加等级值
< 包含,降低等级值
() 把词组成子表达式,允许这些子表达式作为一个组被包含、排序、排列等
~ 取消一个词的等级值
* 词尾通配符
“” 定义一个短语(与单个词的列表不同,它匹配整个短语以便包含或排除这个短语)

全文本搜素使用说明:

  • 在搜素全文本数据时,短词被忽略且从索引中排除。短词定义为那些具有3个或3个以下字符的词
  • Mysql带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略。
  • 许多词出现的频率很高,搜索它们没有用处(返回太多的结果),因此,mysql规定了一个50%的规则,如果一次出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于in boolean mode
  • 如果表中的行数<3行,则全文本搜索不返回结果(因为每个次或者不出现,或者至少出现50%的行中)
  • 忽略词中的单引号。
  • 不具有词的分隔符的语言不能恰当地返回全文本搜索结果
  • 仅在MyISAM数据库引擎中支持全文本中搜索
# 全文本搜索仅支持MyISAM引擎
SELECTnote_text
FROMproductnotes
WHERE#match:要搜索的列,against:要匹配的文本MATCH ( note_text ) against ( 'rabbit' );# 虽然like模糊查询也可实现但排序是随机的,全文本匹配可以按照文本匹配程度由高到底排序
SELECTnote_text
FROMproductnotes
WHEREnote_text LIKE '%rabbit%';# 查询扩展:不止全文本匹配除你想的文本,还搜索出可能与之相关的行
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( 'anvils' );SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( 'anvils' WITH QUERY expansion );# 布尔操作符
# 没有使用布尔操作符
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( 'heavy' IN boolean MODE );# 使用布尔操作符:-排除,*截断(=通配)
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( 'heavy -rope*' IN boolean MODE );# +必须包含:说明同时包含rabbit bait
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( '+rabbit +bait' IN boolean MODE );# 没有+,说明rabbit bait中至少一个都行
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( 'rabbit bait' IN boolean MODE );# "rabbit bait"是匹配短语rabbit bait
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( '"rabbit bait"' IN boolean MODE );# >:增加等级值,<:减少等级值
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( '>rabbit <bait"' IN boolean MODE );# ();把词组成子表达式,允许这些子表达式作为一个组被包含、排除、排列等
SELECTnote_text
FROMproductnotes
WHEREMATCH ( note_text ) against ( '+safe +(<combination)"' IN boolean MODE );

19 插入数据

# 未指定列名的插入:是不安全的,不推荐这么插入
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 );
# 单条数据,书写繁琐,优点是性能比多条数据一次插入快
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. Martin', '100 Main Street', 'Los Angeles', 'CA', '90046', 'USA' );# 多条同时插入:优点是书写简单,缺点性能没有单条数据逐行插入快
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. Martin','100 Main Street','Los Angeles','CA','90046','USA' );
  • insert + select操作:没有了values
# 创建custnew表,模拟insert select操作
CREATE TABLE custnew (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;# 复制customers表中一行数据到custnew中,注意将主键cust_id修改为customers中未出现的主键值
INSERT INTO `learn_mysql`.`custnew` ( `cust_id`, `cust_name`, `cust_address`, `cust_city`, `cust_state`, `cust_zip`, `cust_country`, `cust_contact`, `cust_email` )
VALUES( 20001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com' );# insert select操作,将一条查询语句结果插入到另一个表中,注意是所有查询的数据全部插入
INSERT INTO customers ( cust_id, cust_contact, cust_email, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country ) SELECTcust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country FROMcustnew;

20 更新和删除数据

更新和删除的指导原则

  • 除非实在打算删除更新和删除每一行,否则绝不使用不带where字句的update,delete语句
  • 保证每个表都有主键,尽可能像where字句那样使用它
  • 在对update或delete语句使用where时,最好先用select保证where过滤的正确性
  • 使用强制实施引用完整性的数据库,mysql将不允许删除具有其他表关联的数据行
# update更新语句要与where搭配使用,否则将更新整个列的数据
UPDATE customers
SET cust_email = 'elmer@fudd.com'
WHEREcust_id = 10005;
# 更新多个列
UPDATE customers
SET cust_name = 'The Fudds',
cust_email = 'elmer@fudd.com'
WHEREcust_id = 10005;# delete删除也得搭配where使用,否则也是删除全部数据
# 如果想表中删除所有行,用delete;删除原来的表并重新创建一个,用truncate table
DELETE
FROMcustomers
WHEREcust_id = 10006;

21 创建和操作数据库表

使用auto_increment:

  • 每个表只允许一个auto_increment列,并且它碧玺被索引(比如让它成为主键)
  • select last_insert_id()查询最后一次auto_increment的值

引擎类型:

  • InnoDB是一个可靠的事务处理引擎,但是不支持全文本搜索
  • Memery在功能上等于MyISAM,但由于数据存储在内存,速度很快(适用于临时表)
  • MyISAM是一个性能极高的引擎,它支持全文本搜索,但不支持事务
  • 外键不能跨引擎使用,所以定义表就显得尤其重要
# 创建表:create table table
CREATE TABLE customers
(# AUTO_INCREMENT每个表只能有一个,并且必须被索引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;# select last_insert_id()查询最后一次auto_increment的值
select last_insert_id();CREATE TABLE orderitems
(order_num  int          NOT NULL ,order_item int          NOT NULL ,prod_id    char(10)     NOT NULL ,quantity   int          NOT NULL default 1,# 不指定插入默认是1item_price decimal(8,2) NOT NULL ,PRIMARY KEY (order_num, order_item) # 两个主键
) ENGINE=InnoDB;CREATE TABLE productnotes
(note_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;# 指定引擎为MyISAM
# 更新表alter table xx
# 增加一列
ALTER TABLE vendors ADD vend_phone CHAR ( 20 );
# 删除一列
ALTER TABLE vendors DROP COLUMN vend_phone;
# 修改一列
ALTER TABLE vendors MODIFY COLUMN vend_id INT ( 255 );
# alter创建外键
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 );
# 删除整个表
DROP TABLE custnew;
# 重命名一个表
RENAME TABLE customers TO customers1;
RENAME TABLE customers1 TO customers;

22 使用视图

视图:相当于对一个较复杂的sql进行了一层包装 = 隐藏复杂sql,下次直接使用这个封装调用结果 = 简化复杂sql

  • 是虚拟的表,是mysql对select语句的封装,可用来简化数据处理以及重新格式化基础数据或保护基础数据

  • 视图本身不包含数据,因此他们返回的数据是从其他表中检索出来的。在添加和改变这些表中的数据时,视图将返回改变过的数据

  • crate view创建视图,show craete view viewname查看创建的视图

  • drop view删除视图

  • 更新视图时,可以吸纳drop再crate,或者 create or replace view

  • 如果视图定义中有如下操作,则视图不能更新,需要手动删除视图再创建,一般来说视图只用来查询!

    • 分组(group by和having)
    • 联结
    • 子查询
    • 聚集函数
# 第15章的多表联结查询,可以使用视图将它封装
SELECTcust_name,cust_contact
FROMcustomers,orders,orderitems
WHEREcustomers.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num AND prod_id = 'TNT2';# 创建视图,CREATE VIEW tablename AS + 原先的复杂sql
CREATE VIEW productcustomers AS SELECTcust_name,cust_contact, prod_id FROMcustomers,orders,orderitems WHEREcustomers.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num;
# 使用之前创建的视图productcustomers
SELECTcust_name,cust_contact
FROMproductcustomers
WHEREprod_id = 'TNT2';# 视图另一个重要作用:可以便于重新格式化之前的数据
CREATE VIEW vendorlocations AS # 第10章这条sql结果如果需要反复使用,可以使用视图SELECTCONCAT( Rtrim( vend_name ), ' (', Rtrim( vend_country ), ')' ) AS vend_title FROMvendors ORDER BYvend_name;# 调用刚才创建的视图vendorlocations
SELECT*
FROMvendorlocations;# 创建视图过滤不想要的数据
CREATE VIEW customeremaillist AS SELECTcust_id,cust_name,cust_email FROMcustomers WHEREcust_email IS NOT NULL;SELECT*
FROMcustomeremaillist;# 创建视图,保存计算结果,便于where使用
CREATE VIEW orderitemsexpanded AS SELECTorder_num,prod_id,quantity,item_price,quantity * item_price AS expanded_price FROMorderitems;SELECT*
FROMorderitemsexpanded
WHEREorder_num = 20005;

23 使用存储过程

# 初识存储过程
CREATE PROCEDURE productpricing ()
BEGINSELECTavg( prod_price ) FROMproducts;END;
# 调用存储过程,注意这里就算有参数接受,也不会显示任何值
CALL productpricing ();
# 删除存储过程,不需要()括号
DROP PROCEDURE productpricing;# mysql只支持in、out、inout三个类型的函数参数
# out:相当于函数返回值的定义
CREATE PROCEDURE productpricing ( OUT pl DECIMAL ( 8, 2 ), OUT ph DECIMAL ( 8, 2 ), OUT pa DECIMAL ( 8, 2 ) )
BEGINSELECTmin( prod_price ) INTO pl FROMproducts;SELECTmax( prod_price ) INTO ph FROMproducts;SELECTavg( prod_price ) INTO pa FROMproducts;
END;# mysql变量都以@开头,是一段临时存储的数据
# 调用存储过程,用三个变量接受
CALL productpricing ( @pricelow, @pricehigh, @priceavg );
# 使用这三个变量
SELECT@pricelow,@pricehigh,@priceavg ;# IN:相当于函数参数的定义
CREATE PROCEDURE ordertotal ( IN onumber INT, OUT ototal DECIMAL ( 8, 2 ) )
BEGINSELECTsum( item_price * quantity ) FROMorderitems WHEREorder_num = onumber INTO ototal;
END;
# 查询20005订单的合计价格
CALL ordertotal ( 20005, @totoal );SELECT@totoal;

存储过程综合运用:建立智能存储过程,需求是对订单合计增加营业税,步骤如下:

  1. 获得合计(与以前一样)
  2. 把营业税有条件地添加到合计
  3. 返回合计
CREATE PROCEDURE ordertotal ( IN onumber INT, IN taxable boolean, OUT ototal DECIMAL ( 8, 2 )
) COMMENT '选择性计算有/无税收下的订单总价'
BEGIN# 定义临时变量totalDECLARE total DECIMAL ( 8, 2 );# 税率为6个点DECLARE taxrate INT DEFAULT 6;# 查询出无税收时订单总价SELECTsum( quantity * item_price ) FROMorderitems WHEREorder_num = onumber INTO total;# 如果有税收,算出税收总价IFtaxable THENSELECTtotal +(total / 100 * taxrate ) INTO total;END IF;# 临时变量传递给结果参数SELECTtotal INTO ototal;END;CALL ordertotal ( 20005, 0, @total );
SELECT@total;CALL ordertotal ( 20005, 1, @total );
SELECT@total;
# 查看存储过程等详细信息
SHOW PROCEDURE STATUS;

24 使用游标

为什么使用游标:

  • 需要在检索出来的行中前进或后退一行或多行。这就是使用游标的原因

使用游标步骤:

  1. 在能够使用游标前,必须声明它。这个过程实际上没有检索数据,它只是定义要使用的select语句
  2. 一旦声明后,必须打开游标以供使用。这个过程用前面定义的select语句把游标实际检索出来
  3. 对于填有数据的游标,根据需要取出各行
  4. 在结束游标使用时,必须关闭游标
CREATE PROCEDURE processorders ( OUT outnumber INT
)
BEGIN# 临时变量DECLARE o INT;# 创建游标DECLARE  ordernumbers CURSOR FOR SELECTorder_num FROMorders;# 开启游标OPEN ordernumbers;# 使用游标FETCH ordernumbers INTO o;# 返回数据给函数参数SELECTo INTO outnumber;# 关闭游标CLOSE ordernumbers;
END;CALL processorders ( @outnumber );
SELECT@outnumber;

25 触发器

为什么要使用触发器?

  • 要某条语句(或某些语句)在事件发生时自动执行

  • 触发器只对insert、delete、update有用

  • mysql5以后不支持触发器返回结果,自己手动添加一个变量@变量名,返回该结果可以看到触发器结果;

初识触发器:

# 初识触发器:当每次往products表中添加一行数据时,列为addPro记录一条“Product added”
CREATE TRIGGER newproduct AFTER INSERT ON products
FOR EACH ROWSELECT'Product added' INTO @addPro;INSERT INTO products ( prod_id, vend_id, prod_name, prod_price, prod_desc )VALUES( "ANV0111", "1001", "3 ton anvil", 2.33, "good" );SELECT@addPro;

insert触发器:

  • 在insert触发器代码内,可以用一个名为new的虚拟表,访问被插入的行
  • 在before insert触发器中,new中的值也可以被更新(允许更改被插入的值)
  • 对于auto_increment列,new在insert执行之前包含0,在insert之后包含新的自动生成值
# insert触发器:可以访问一个虚拟表NEW
CREATE TRIGGER neworder AFTER INSERT ON orders
FOR EACH ROW# insert有一个虚拟的NEW表,表示访问被插入的那一行# NEW.order_num:访问那一行的order_num列SELECT NEW.order_num INTO @neworderRes;INSERT INTO orders ( order_date, cust_id )VALUES( Now(), 10001 );SELECT@neworderRes;DROP TRIGGER neworder;

delete触发器:

  • 在delete触发器代码内,可以引用一个名为old的虚拟表,访问被删除的行
  • old中的值全是只读的,不能更新
# delete触发器:任意订单被删除之前,old都将结果存回achive_orders表中
CREATE TRIGGER deleteorder BEFORE DELETE ON orders
FOR EACH ROW
BEGIN# 任意订单被删除前将执行此触发器。使用一条INSERT语句将OLD中的值(要被删除的订单)保存到一个名为archive orders的存档表中INSERT INTO achive_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中的值全是只读的,不能更新
# update触发器:new和old都可以使用
CREATE TRIGGER updatevender BEFORE UPDATE ON vendors
FROM EACH ROWSET new.vend_state = upper( new.vend_state ) INTO @updatevenderRes;

触发器注意事项:

  1. 与其他DBMS相比,MySQL 5中支持的触发器相当初级。未来的MySQL版本中有一些改进和增强触发器支持的计划。
  2. 创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果INSERT、UPDATE或DELETE语句能够执行,则相关的触发器也能执行。
  3. 应该用触发器来保证数据的一致性(大小写、格式等)。在触发器中执行这种类型的处理的优点是它总是进行这种处理,而且是透明地进行,与客户机应用无关。
  4. 触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,把更改(如果需要,甚至还有之前和之后的状态)记录到另一个表非常容易。
  5. 遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。

26 管理事务处理

  • 事务(transaction):指一组sql语句
  • 回退(rollback):指撤销指定sql的过程
  • 提交(commit):值将未存储的sql语句结果写入数据库表
  • 保留点(savepoint):指事务处理设置中的临时占位符(place-holder,可以对它发布回退)
# 开启事务:学习回滚
START TRANSACTION;SELECT* FROMorderitems;DELETE FROMorderitems;SELECT* FROMorderitems;
# 回退事务,TRANSACTION之后的语句全部不执行
ROLLBACK;SELECT*
FROMorderitems;# 开启事务:学习commit
START TRANSACTION;DELETE FROMorderitems WHEREorder_num = 20010;DELETE FROMorders WHEREorder_num = 20010;
# 事务块内,commit提交一段sql,前提是没报错
COMMIT;# 开启事务:设置保留点START TRANSACTION;# 设置一个事务的保留点()SAVEPOINT deletel;# 如果出现问题,就回退到设置的保留点ROLLBACK TO deletel;# autocommit标志决定是否自动提交更改,不管有没有COMMIT语句。设置autocommit为0(假)指示MySQL不自动提交更改(直到autocommit被设置为真为止)。
# autocommit标志是针对每个连接而不是服务器的。
SET autocommit = 0;
SET autocommit = 1;

27 全球化和本地化

# 显示所有可用的字符集,以及他们默认的校队
SHOW CHARACTER SET;
# 显示所有可用的校队,以及他们默认的字符集
SHOW COLLATION;
# 显示所有的字符集和校队的名字
SHOW VARIABLES LIKE 'character%';
SHOW VARIABLES LIKE 'collation%';
# 创建表指定字符集和校队方式
CREATE TABLE mytable ( column1 INT, column2 VARCHAR ( 10 )
) ENGINE = INNODB DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;CREATE TABLE mytable1 ( column1 INT, column2 VARCHAR ( 10 ), column3 VARCHAR ( 100 ) CHARACTER SET latin1 COLLATE latin1_general_ci
) ENGINE = INNODB DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;# 查询语句时order by指定校队方式SELECT*
FROMcustomers
ORDER BYcust_name COLLATE utf8_general_ci;

28 安全管理

# mysql的用户权限,放在mysql库(默认的一个库)里的user表(默认有的一个表)
USE mysql;
SELECT*
FROMUSER;# 创建一个数据库用户:ben
# 账户:ben
# 密码:password
CREATE USER ben IDENTIFIED BY 'password';# 但是这样创建的用户没有任何权限,查询一下就知道
SELECT*
FROMUSER;
# 重命名数据库用户名
RENAME USER ben TO ben1;
RENAME USER ben1 TO ben;
# 查看ben用户的权限
SHOW GRANTS FOR ben;
# 给ben用户添加learn_mysql库的查询权限
GRANT SELECT ONlearn_mysql.* TO ben;
# 撤销ben用户查询权限
REVOKE SELECT ONlearn_mysql.* TO ben;
# 修改用户密码,但是必须有权限才行
SET PASSWORD FOR ben = PASSWORD ( 'password1' );
# 不指定用户名,默认是修改本次登录的用户的密码
SET PASSWORD = PASSWORD ( 'password1' );

29 数据库维护

# analyze:分析表建是否有问题
ANALYZE TABLE orders;# check:检查一个表
CHECK TABLE orders,orderitems;

30 改善性能

  • 查看当前配置:show variables;show status;

  • 显示所有进程:show processlist(服务器上查看ip非常有用)

  • explain来查看select语句性能,再优化

  • 绝不要检索比需求还要多的数据,也就是select * 减少使用

  • select 检索数据时or使用过多,可以用union来拼接多条select语句,性能好很多

  • like很慢,最好是使用fulltext而不是like

《mysql必知必会》学习笔记相关推荐

  1. 第二行代码学习笔记——第六章:数据储存全方案——详解持久化技术

    本章要点 任何一个应用程序,总是不停的和数据打交道. 瞬时数据:指储存在内存当中,有可能因为程序关闭或其他原因导致内存被回收而丢失的数据. 数据持久化技术,为了解决关键性数据的丢失. 6.1 持久化技 ...

  2. 第一行代码学习笔记第二章——探究活动

    知识点目录 2.1 活动是什么 2.2 活动的基本用法 2.2.1 手动创建活动 2.2.2 创建和加载布局 2.2.3 在AndroidManifest文件中注册 2.2.4 在活动中使用Toast ...

  3. 第一行代码学习笔记第八章——运用手机多媒体

    知识点目录 8.1 将程序运行到手机上 8.2 使用通知 * 8.2.1 通知的基本使用 * 8.2.2 通知的进阶技巧 * 8.2.3 通知的高级功能 8.3 调用摄像头和相册 * 8.3.1 调用 ...

  4. 第一行代码学习笔记第六章——详解持久化技术

    知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...

  5. 第一行代码学习笔记第三章——UI开发的点点滴滴

    知识点目录 3.1 如何编写程序界面 3.2 常用控件的使用方法 * 3.2.1 TextView * 3.2.2 Button * 3.2.3 EditText * 3.2.4 ImageView ...

  6. 第一行代码学习笔记第十章——探究服务

    知识点目录 10.1 服务是什么 10.2 Android多线程编程 * 10.2.1 线程的基本用法 * 10.2.2 在子线程中更新UI * 10.2.3 解析异步消息处理机制 * 10.2.4 ...

  7. 第一行代码学习笔记第七章——探究内容提供器

    知识点目录 7.1 内容提供器简介 7.2 运行权限 * 7.2.1 Android权限机制详解 * 7.2.2 在程序运行时申请权限 7.3 访问其他程序中的数据 * 7.3.1 ContentRe ...

  8. 第一行代码学习笔记第五章——详解广播机制

    知识点目录 5.1 广播机制 5.2 接收系统广播 * 5.2.1 动态注册监听网络变化 * 5.2.2 静态注册实现开机广播 5.3 发送自定义广播 * 5.3.1 发送标准广播 * 5.3.2 发 ...

  9. 第一行代码学习笔记第九章——使用网络技术

    知识点目录 9.1 WebView的用法 9.2 使用HTTP协议访问网络 * 9.2.1 使用HttpURLConnection * 9.2.2 使用OkHttp 9.3 解析XML格式数据 * 9 ...

  10. 安卓教程----第一行代码学习笔记

    安卓概述 系统架构 Linux内核层,还包括各种底层驱动,如相机驱动.电源驱动等 系统运行库层,包含一些c/c++的库,如浏览器内核webkit.SQLlite.3D绘图openGL.用于java运行 ...

最新文章

  1. Hibernate+Spring-orm的基本方法总结
  2. python创建文件并写入-python新建txt文件,并逐行写入数据
  3. Oracle 11g R2 64位在 win7 64位的安装流程图解
  4. 统计学要学的计算机课程有哪些,统计学专业主要课程学什么_课程设置安排及分类...
  5. VTK:可视化之TextSource
  6. 2021牛客暑期多校训练营2 L-WeChat Walk(分块)
  7. 建立单链表 单链表的插入_单链列表插入
  8. ssm 转发请求_千呼万唤!阿里内部终于把这份SSM框架技术学习笔记分享出来了...
  9. python代码编辑器、最好_这十大文本/代码编辑器最好用
  10. html内嵌样式字体,html-通过内联C加载外部字体
  11. fibonacci数列python_从 Python 计算 Fibonacci 数列说起
  12. 愤怒的小鸟4只编外鸟_幼儿园小班游戏教案小鸟找食
  13. python飞机大战素材黑马_Python基础day12飞机大战(上)
  14. PLC对接SQL数据库,实现数据采集和边缘计算
  15. 【IDEA】如何修改已创建的文件类型,虽然很无脑,但是也很棘手
  16. 2020中国邮政总行信息技术岗校招笔试经历
  17. 学习期间的感悟和个人写的一段歌词
  18. 《中国通史 2016》_12_读后感
  19. Line 14: Char 23: runtime error: signed integer overflow: 746384741 * 10 cannot be represented
  20. java jsf 入门_JSF入门、简单示例

热门文章

  1. 六种人类天性基本倾向
  2. 掌握哪些知识,才能被称得上一名合格的前端开发工程师?
  3. 工作组可以看到计算机 但是无法访问,Win7中工作组计算机无法访问解决技巧
  4. stata domin
  5. 合唱队形java_合唱队形
  6. 爬虫:信息提取的一般方法
  7. KVM:将img文件转换成qcow2格式的镜像
  8. 该填志愿了,国内大学计算机专业哪家强?
  9. 古代的时辰是怎样划分的
  10. Java随机生成4位随机数字+字母