Mysql必知必会


第一章 数据库基础

基本概念

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

  • (table):某种特定类型数据的结构化清单。

  • 模式(schema):关于数据库和表的布局及特性的信息。

  • (column):表中的一个字段。所有表都是由一个或多个列组成的。

  • 数据类型(datatype):所容许的数据的类型。每个表列都有相应的数据类型,它限制(或容许)该列中存储的数据。

  • (row):表中的一个记录。

  • 主键(primary key):列(或一组列),其值能够唯一区分表中每个行。

SQL

SQL(发音为字母S-Q-L或sequel)是结构化查询语言(Structured Query Language)的缩写。SQL是一种专门用来与数据库通信的语言。


第二章 Mysql简介

终端进入命令

$ mysql -u root -p

-u 用户名,-p(小写) 输入密码, -h 主机名, -P (大写)端口,注意此时的大小写。 mysql --help 命令行选项和参数列表。

创建测试数据库

-- 创建数据库
CREATE DATABASE mytestdb;
-- 使用数据库
-- 必须先使用USE打开数据库,才能读取其中的数据。
USE mytestdb;
-- 执行sql脚本
创建测试表
########################
# 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);

创建测试数据

##########################
# 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.'
);

第三章 了解数据库和表

  • 使用数据库

use mytestdb;
  • 显示可用的数据库列表

SHOW DATABASES;
  • 获得一个数据库内的表的列表

SHOW TABLES;
  • 用来显示表列

SHOW COLUMNS FROM customers;
DESCRIBE customers;
  • 其他SHOW语句

SHOW STATUS -- 用于显示广泛的服务器状态信息
SHOW CREATE DATABASE -- 显示创建特定数据库的MySQL语句
SHOW CREATE TABLE -- 显示创建特定表的语句
SHOW GRANTS -- 显示授予用户(所有用户或特定用户)的安全权限
SHOW ERRORS -- 显示服务器错误
SHOW WARNINGS -- 警告信息

第四章 检索数据

  • 检索指定的单个列

-- 检索products表中的prod_name列
SELECT prod_name FROM products;
  • 检索指定的多个列

-- 检索products表中的prod_id,prod_name和prod_price列
SELECT prod_id, prod_name, prod_price FROM products;
  • 检索表中的所有列

-- 检索products表中的所有列
SELECT * FROM products;
  • 数据查询去重

-- DISTINCT关键字必须直接放在列名的前面,不能部分使用DISTINCT,DISTINCT关键字应用于所有列而不仅是前置它的列。
SELECT DISTINCT vend_id FROM products;
  • 限制查询结果的条数

-- 返回不多于5行
SELECT prod_name FROM products LIMIT 5;
-- 返回从第5行开始的5行
SELECT prod_name FROM products LIMIT 5,5;

第五章 排序检索数据

  • 按指定列进行排序

SELECT prod_name
FROM products
ORDER BY prod_name;
  • 按多个指定列进行排序

SELECT prod_id, prod_price, prod_name
FROM products
ORDER BY prod_price, prod_name;

对于上述例子中的输出,仅在多个行具有相同的prod_price值时才对产品按prod_name进行排序。如果prod_price列中所有的值都是唯一的,则不会按prod_name排序。

  • 默认使用升序排列ASC,降序需要加上DESC

SELECT prod_id, prod_price, prod_name
FROM products
ORDER BY prod_price DESC;
?
SELECT prod_id, prod_price, prod_name
FROM products
ORDER BY prod_price DESC, prod_name;

DESC关键字只应用到直接位于其前面的列名。上例中,只对prod_price列指定DESC,对prod_name列不指定。 升序关键字ASC,可省略。

  • 找出一列中最高或最低的值

select prod_price from products order by prod_price DESC LIMIT 1;

给出ORDER BY句子时,应保证位于FROM句子之后,如果使用LIMIT,应位于ORDER BY之后。

第六章 过滤数据

使用WHERE子句

-- 返回prod_price为2.50的行
SELECT prod_name, prod_price FROM products WHERE prod_price = 2.50

WHERE子句操作符

符号说明
= 等于
<> 不等于
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
BETWEEN 在指定的两个值之间

查询示例

-- 检查单个值
-- 返回prod_name为Fuses的一行(匹配时默认不区分大小写)
SELECT prod_name, prod_price FROM products WHERE prod_name = 'fuses';
?
-- 列出小于10美元的所有产品
SELECT prod_name, prod_price FROM products WHERE prod_price < 10;
?
-- 列出小于等于10美元的所有产品
SELECT prod_name, prod_price FROM products WHERE prod_price <= 10;
?
-- 不匹配检查
-- 列出不是1003的所有产品
SELECT vend_id, prod_name FROM products WHERE vend_id <> 1003;
SELECT vend_id, prod_name FROM products WHERE vend_id != 1003;
?
-- 范围值检查
-- 检索价格在5-10美元之间的所有产品
SELECT prod_name, prod_price FROM products
WHERE prod_price BETWEEN 5 AND 10;
?
-- 空值检查
-- 返回价格为空的所有产品
SELECT prod_name FROM products WHERE prod_price IS NULL;

第七章 数据过滤

运算等级运算符
1 !
2 -(负号)、~(按位取反)
3 ^(按位异或)
4 *、/(DIV)、%(MOD)
5 +、-
6 >>、<<
7 &
8 |
9 =(比较运算)、<=>、<、<=、>、>=、!=、<>、IN、IS NULL、LIKE、REGEXP
10 BETWEEN AND、CASE、WHEN、THEN、ELSE
11 NOT
12 &&、AND
13 XOR
14 ||、OR
15 =(赋值运算)、:=

代码示例

-- AND操作符
-- 检索由1003制造且价格小于等于10美元的所有产品的名称和价格
SELECT prod_id, prod_price, prod_name FROM products
WHERE vend_id = 1003 AND prod_price <= 10;
?
-- OR操作符
-- 检索由1002和1003制造的产品的名称和价格
SELECT prod_name, prod_price FROM products
WHERE vend_id = 1002 or vend_id = 1003;
?
-- 计算次序
-- AND的优先级高于OR【见上表】
SELECT prod_name, prod_price FROM products
WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;
?
-- IN操作符
-- 用来指定条件范围,取合法值的由逗号分隔的清单全部在圆括号中。
-- IN比OR执行更快,最大的优点是可以包含其他SELECT语句,能够更动态地建立WHERE子句
SELECT prod_name, prod_price FROM products WHERE vend_id IN (1002, 1003)
ORDER BY prod_name;
?
-- NOT操作符
-- 列出除1002,1003之外所有供应商供应的产品
SELECT prod_name, prod_price FROM products WHERE vend_id NOT IN (1002, 1003)
ORDER BY prod_name;

第八章 使用通配符进行过滤

LIKE操作符

LIKE指示MYSQL,后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。

-- 百分号(%)通配符
-- 表示任何字符出现任意次数
-- 例:找出所有jet起头的产品
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE 'jet%';
?
-- 例:使用多个通配符,匹配任何位置包含anvil的值,不论它之前或之后出现什么字符
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '%anvil%';
?
-- 例:找出s起头e结尾的所有产品
SELECT prod_name FROM products WHERE prod_name LIKE 's%e';

%可以匹配0个字符,%代表搜索模式中给定位置的0个、1个或多个字符 尾空格可能会干扰通配符,例如,在保存词anvil时,如果它后面有一个或多个空格,则子句WHERE prod_name LIKE '%anvil'将不会匹配它们,因为在最后的l后有多余的字符。解决这个问题的一个简单的办法是在搜索模式最后附加一个%。一个更好的办法是使用函数(trim)去掉首尾空格。

-- 下划线(_)通配符
-- 只匹配单个字符而不是多个字符
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '_ ton anvil';

使用技巧

  • 不要过度使用通配符,如果其他操作符能够达到目的应该使用其他操作符。

  • 在确实需要使用通配符时,除非绝对有必要,否则不要把它们用在搜索的开始处。 把通配符置于搜索模式的开始处搜索起来是最慢的。

  • 仔细注意通配符的位置。

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

相比于Like通配符,更加灵活

基本字符匹配

-- 例:检索prod_name包含文本1000的所有行
-- REGEXP后所跟的东西作为正则表达式处理
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;

进行OR匹配

-- `|`为正则表达式的OR操作符,表示匹配其中之一
SELECT prod_name FROM products WHERE prod_name REGEXP '1000|2000'
ORDER BY prod_name;
?
?
-- 可以给出两个以上的OR条件
`1000|2000|3000`

匹配几个字符之一

-- `[]`表示匹配[]中的任意一个字符,例如`[123]`是`[1|2|3]`的缩写
SELECT prod_name FROM products WHERE prod_name REGEXP '[123] Ton'
ORDER BY prod_name;
-- output
+-------------+
| prod_name   |
+-------------+
|1 ton anvil |
|2 ton anvil |
+-------------+
?
-- 和直接使用OR的区别:
SELECT prod_name FROM products WHERE prod_name REGEXP '1|2|3 Ton'
ORDER BY prod_name
?
-- 匹配的是1 OR 2 OR 3 Ton,应该使用'[1|2|3] Ton'
-- output
+-------------+
| prod_name   |
+-------------+
|1 ton anvil |
|2 ton anvil |
|JetPack 1000 |
|JetPack 2000 |
|TNT (1 stick)|
+-------------+

字符集合也可以被否定,为否定一个字集,在集合的开始处放置^,例如123匹配除这些字符的任何东西。

匹配范围

-- `[0123456789]`可以写成`[0-9]`,其他范围如`[a-z]`
SELECT prod_name FROM products WHERE prod_name REGEXP '[1-5] Ton'
ORDER BY prod_name
?
-- output
+-------------+
| prod_name |
+-------------+
| .5 ton anvil|
| 1 ton anvil |
| 2 ton anvil |
+-------------+

匹配特殊字符

-- 匹配'.'字符,如果使用
SELECT vend_name FROM vendors WHERE vend_name REGEXP '.'
ORDER BY vend_name;
?
-- output
+---------------+
|   vend_name   |
+---------------+
| ACME         |
| Anvils R Us   |
| Furball Inc. |
| Jet Set       |
| Jouets Et Ours|
| LT Supplies   |
+---------------+
?
-- 因为'.'为匹配任意字符,因此匹配特殊字符,必须用'\\'为前导
?
SELECT vend_name FROM vendors WHERE vend_name REGEXP '\\.'
ORDER BY vend_name;
?
-- output
+---------------+
|   vend_name   |
+---------------+
| Furball Inc. |
+---------------+

正则表达式中具有特殊意义的所有字符都要通过这种方式转义 \\也用来引用元字符

元字符说明
\\f 换页
\\n 换行
\\r 回车
\\t 制表
\\v 纵向制表
为了匹配\本身,需要使用\\\

匹配字符类

说明
[:alnum:] 任意字母和数字(同[a-zA-Z0-9])
[:alpha:] 任意字符(同[a-zA-Z])
[:cntrl:] 空格和制表(同[\t])
[:digit:] ASCII控制字符(ASCII)0到31和127
[:graph:] 任意数字(同[0-9])
[:lower:] 任意小写字母(同[a-z])
[:print:] 任意可打印字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在内的任意空白字符(同[\f\n\r\t\v])
[:upper:] 任意大写字母(同[A-Z])
[:xdigit:] 任意十六进制数字(同[a-fA-F0-9])

匹配多个实例

元字符 说明

元字符说明
* 0个或多个匹配
+ 1个或多个匹配(等于{1,})
0个或1个匹配(等于{0,1})
{n} 指定数目的匹配
{n,} 不少于指定数目的匹配
{n.m} 匹配数目的范围(m不超过255)

例:

SELECT prod_name FROM products WHERE prod_name REGEXP '\\([0-9] sticks?\\)'
ORDER BY prod_name
-- output
+---------------+
|   prod_name   |
+---------------+
| TNT (1 stick) |
| TNT (5 sticks)|
+---------------+
?
-- '\\('匹配'('
'[0-9]'匹配任意数字
'stick?'匹配'stick'和'sticks'
'\\)'匹配')'

例:匹配连在一起的4位数字

SELECT prod_name FROM products WHERE prod_name REGEXP '[[:digit:]]{4}'
ORDER BY prod_name;
-- output
+---------------+
|   prod_name   |
+---------------+
| JetPack 1000 |
| JetPack 2000 |
+---------------+
-- 也可以写成 '[0-9][0-9][0-9][0-9]'

定位符

元字符说明
^ 文本的开始
$ 文本的结尾
[:<:] 词的开始
[:>:] 词的结尾

例:找出以一个数(包括小数点开头)开始的所有产品

SELECT prod_name FROM products WHERE prod_name REGEXP '^[0-9\\.]'
ORDER BY prod_name;
-- output
+---------------+
|   prod_name   |
+---------------+
| .5 ton anvil |
| 1 ton anvil   |
| 2 ton anvil   |
+---------------+

第十章 创建计算字段

计算字段

应用程序需要的数据需要通过从数据库中检索出转换、计算或格式化过的数据,而不是检索出数据,然后再在客户机应用程序或报告程序中重新格式化。

字段:基本上与列的意思相同,经常互换使用,不过数据库一般称为列,而属于字段通常用在计算字段的连接上。

拼接字段(Concat()

拼接:将值联结到一起构成单个值

在SELECT语句中,可使用Concat()函数来拼接两个列。Concat()函数需要一个或多个指定的串,各个串之间用逗号分隔。

SELECT Concat(vend_name, ' (',vend_country,')') FROM vendors
ORDER BY vend_name;
#output
+-----------------------------------------+
| Concat(vendname,' (',vend_country,')') |
+-----------------------------------------+
| ACME (USA)                             |
| Anvils R Us (USA)                       |
| Furball Inc. (USA)                     |
| Jet Set (England)                       |
| Jouets Et Ours (France)                 |
| LT Supplies (USA)                       |
+-----------------------------------------+

使用 RTrim()函数可以删除右侧多余的空格来整理数据,例:

SELECT Concat(RTrim(vend_name),' (',RTrim(vend_country), ')')
FROM vendors
ORDER BY vend_name;
函数说明
Trim() 去掉两边的空格
LTrim() 去掉左边的空格
RTrim() 去掉右边的空格

使用别名

拼接的结果只是一个值,未命名。可以用AS关键字赋予别名

常见的用途包括在实际的表列名包含不符合规定的字符(如空格)时重新命名它,在原来的名字含混或容易误解时扩充它等等。 别名有时也称为导出列(derived column)

SELECT Concat(RTrim(vend_name),' (',RTrim(vend_country), ')') AS vend_title
FROM vendors
ORDER BY vend_name;
#output
+----------------------------+
| vend_name                 |
+----------------------------+
| ACME (USA)                 |
| Anvils R Us (USA)         |
| Furball Inc. (USA)         |
| Jet Set (England)         |
| Jouets Et Ours (France)   |
| LT Supplies (USA)         |
+----------------------------+
#指示SQL创建一个包含指定计算的名为vend_title的计算字段

执行算术计算

例:汇总物品的价格(单价乘以订购数量)

SELECT prod_id,
  quantity,
      item_price,
      quantity * item_price AS expanded_price
FROM orderitems
WHERE order_num = 20005;
#output
+---------+----------+------------+----------------+
| prod_id | quantity | item_price | expanded_price |
+---------+----------+------------+----------------+
| ANV01   |       10 |       5.99 |          59.90 |
| ANV02   |        3 |       9.99 |          29.97 |
| TNT2   |        5 |      10.00 |          50.00 |
| FB     |        1 |      10.00 |          10.00 |
+---------+----------+------------+----------------+
操作符说明
+
-
*
/

SELECT Now()利用 Now()函数返回当前日期和时间。

第十一章 使用数据处理函数

函数没有SQL的可移植性强

使用函数

大多数SQL实现支持以下类型的函数

  • 用于处理文本串的文本函数

  • 在数值数据上进行算术操作的数值函数

  • 处理日期和时间值并从这些值中提取特定成分的日期和时间函数

  • 返回DBMS正是用的特殊信息的系统函数

文本处理函数

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

SOUNDEX是一个将任何文本转换为描述其语音表示的字母数字模式的算法,使得能对串进行发音比较而不是字母比较。MySQL提供对SOUNDEX的支持。

例:联系人Y.Lie输入错误为Y.Lee,使用SOUNDEX检索,匹配发音类似于Y.Lie的联系名

SELECT cust_name, cust_contact FROM customers
WHERE Soundex(cust_contact)= Soundex('Y Lie');
#output
+-------------+--------------+
| cust_name   | cust_contact |
+-------------+--------------+
| Coyote Inc. | Y Lee       |
+-------------+--------------+

日期和时间处理函数

函数说明
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() 返回一个角度的正弦
Sqrt() 返回一个数的平方根
Tan() 返回一个角度的正切

第十二章 汇总数据

函数说明
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和

AVG()函数(求平均值)

SELECT AVG(prod_price) AS avg_price FROM products;

例:返回特定供应商所提供产品的平均价格

SELECT AVG(prod_price) AS avg_price
FROM products
WHERE vend_id = 1003;

COUNT()函数(统计条数)

SELECT COUNT(*) AS num_cust FROM customers;

MAX()函数(取最大值)

SELECT MAX(prod_price) AS max_price
FROM products;

MAX()函数忽略列值为NULL的行。

MIN()函数(取最小值)

SELECT MIN(prod_price) AS min_price FROM products;

SUM()函数(统计总数)

SELECT SUM(quantity) AS items_ordered
FROM orderitems
WHERE order_num = 20005;

例:合计计算值,合计每项物品item_price*quantity,得出订单总金额

SELECT SUM(item_price*quantity) AS total_price
FORM orderitems
WHERE order_num = 20005;

组合聚集函数

SELECT语句可根据需要包含多个聚集函数

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;
#output
+-----------+-----------+-----------+-----------+
| num_items | price_min | price_max | price_avg |
+-----------+-----------+-----------+-----------+
|        14 |      2.50 |     55.50 | 16.133571 |
+-----------+-----------+-----------+-----------+

第十三章 分组数据

创建分组

例:根据vend_id分组,对每个分组分别计算总数

SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id;
?
#output
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
+---------+-----------+

使用with rollup关键字,可以统计得到每个分组的值,和分组的总值。

SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id WITH ROLLUP;
?
#output
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
|         |        14 |
+---------+-----------+

使用having过滤分组数据

SELECT cust_id, COUNT(*) AS orders
FROM orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
#output
+---------+--------+
| cust_id | orders |
+---------+--------+
|   10001 |      2 |
+---------+--------+

WHERE不起作用,因为过滤是基于分组聚集值而不是特定行值的。

例:列出具有2个(含)以上、价格为10(含)以上的产品的供应商

SELECT vend_id, COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10
GROUP BY vend_id
HAVING COUNT(*) >=2
#output
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1003 |         4 |
|    1005 |         2 |
+---------+-----------+

分组和排序

例:检索总计订单价格大于等于50的订单的订单号和总计订单价格.

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 要返回的列或表达式
WHERE 从中检索数据的表 仅在从表选择数据时使用
GROUP BY 分组说明 尽在按组计算聚集是使用
HAVING 组级过滤
ORDER BY 输出排序顺序
LIMIT 要检索的行数
解释:
- 先执行 from 关键字后面的语句,明确数据来源,即它是从哪张表取来的
- 接着执行 where 关键字后面的语句,对行数据进行筛选
- 再接着执行 group by 后面的语句,对数据进行分组分类
- 然后执行 select 后面的语句,也就是对处理好的数据,具体要提取哪些字段
- 最后执行 order by 后面的语句,对最终结果进行排序

第十四章 使用子查询

例:列出订购物品TNT2的所有客户

  1. 检索包含物品TNT2的所有订单的编号

  2. 检索具有前一步骤列出的订单编号的所有客户的ID

  3. 检索前一步骤返回的所有客户ID的客户信息

#(1)
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2';
#output
+-----------+
| order_num |
+-----------+
|     20005 |
|     20007 |
+-----------+
#(2)
SELECT cust_id FROM orders WHERE order_num IN (20005,20007);
+-----------+
| cust_id |
+-----------+
|     10001 |
|     10004 |
+-----------+
?
#(1)+(2)
SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num FROM orderitems WHERE prod_id = 'TNT2');
?
+-----------+
| cust_id |
+-----------+
|     10001 |
|     10004 |
+-----------+
?
#(3)
SELECT clust_name. cust_contact FROM customers WHERE cust_id IN (10001, 10004)
?
#(1)+(2)+(3)
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'));
#output
+----------------+--------------+
| cust_name     | cust_contact |
+----------------+--------------+
| Coyote Inc.   | Y Lee       |
| Yosemite Place | Y Sam       |
+----------------+--------------+

作为计算字段使用子查询

需要显示customers表中每个客户的订单总数,订单与相应的客户ID存储在orders表中

  1. 从customers表中检索客户列表

  2. 对于检索出的每个客户,统计其在orders表中的订单数目

# 为了对每个客户执行COUNT(*)计算,应该将COUNT(*)作为一个子查询
SELECT cust_name, cust_state, (SELECT COUNT(*) FROM orders
                             WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers ORDER BY cust_name;

第十五章 联结表

例如:两个表,一个存储供应商信息,另一个存储产品信息。vendors表包含所有供应商信息,每个供应商占一行,每个供应商应具有唯一的标识,称为主键(primary key)。products表只存储产品信息,除了存储供应商ID之外不存储其他的供应商信息。vendors表的主键又叫products的外键,它将vendors表与products表关联,利用供应商ID能从vendors表中找出相应供应商的详细信息。

创建连结

我们把tableA看作左表,把tableB看成右表

INNER JOIN是选出两张表都存在的记录:

LEFT OUTER JOIN是选出左表存在的记录:

RIGHT OUTER JOIN是选出右表存在的记录:

FULL OUTER JOIN则是选出左右表都存在的记录:

两个表用WHERE子句联结
SELECT vend_name, prod_name, prod_price FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;
内部连结
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;

联结多个表

单纯使用where进行连表查询
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;
#显示编号为20005的订单中的物品。订单物品存储在orderitems表中,按每个产品的ID存储。
它引用products表中的产品。这些产品通过供应商ID联结到vendors表中相应的供应商
使用外连接进行连表查询
SELECT prod_name, vend_name, prod_price, quantity
from products
left join vendors
on products.vend_id = vendors.vend_id
left join orderitems
on orderitems.prod_id = products.prod_id
where order_num = 20005;

第十六章 创建高级联结

使用表别名

字段使用别名
SELECT Concat(RTrim(vend_name),'('Rtrim(vend_country),')') AS vend_title
FROM vendors ORDER BY vend_name;
表使用别名
  • 缩短SQL语句

  • 允许在单条SELECT语句中多次使用相同的表

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';

自联结

例:如果某物品(ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。

#子查询
SELECT prod_id, prod_name
FROM products
WHERE vend_id = (SELECT vend_id FROM products WHERE prod_id = 'DTNTR');
#output
+---------+----------------+
| prod_id | prod_name     |
+---------+----------------+
| DTNTR   | Detonator     |
| FB     | Bird seed     |
| FC     | Carrots       |
| SAFE   | Safe           |
| SLING   | Sling         |
| TNT1   | TNT (1 stick) |
| TNT2   | TNT (5 sticks) |
+---------+----------------+
#使用自联结
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 INNER JOIN orders
ON customers.cust_id = orders.cust_id;
?
#外部联结
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;

这个例子使用左外部联结来包含所有客户,甚至包含那些没有任何下订单的客户。

要分清不同联结方式查询的范围。

使用联结和联结条件

  • 注意所使用的联结类型,一般我们使用内部联结,但使用外部联结也是有效的。

  • 保证使用正确的联结条件,否则将返回不正确的数据。

  • 应该总是提供联结条件,否则会得出笛卡尔积。

  • 在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。应该在一起测试他们前分别测试每个联结。

第十七章 组合查询

组合查询

MySQL允许执行多个查询并将结果作为单个查询结果返回。 两种情况:

  • 在单个查询中从不同的表返回类似结构的数据

  • 对单个表执行多个查询,按单个查询返回数据

使用UNION创建组合查询

给出每条SELECT语句,在各条语句之间放上关键字UNION 例:需要价格小于等于5的所有物品的一个列表,并且包含供应商1001和1002生产的所有物品

#单条语句
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5;
?
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN (1001,1002);
?
#组合上述语句
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN (1001, 1002);
?
#等于
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
OR vend_id IN (1001, 1002);

UNION规则

  • UNION 必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔

  • UNION中的每个查询必须包含先沟通的列、表达式或聚集函数

  • 列数据类型必须兼容:类型不必完全向东,但必须是DBMS可以隐含地转换的类型

包含或取消重复的行

UNION从查询结果集中自动去除了重复的行,如果需要返回所有行,可以使用UNION ALL

对组合查询结果排序

使用ORDER BY子句排序,只能使用一条ORDER BY子句,必须在最后一条SELECT语句之后。

第十九章 插入数据

INSERT

  • 插入完整的行

  • 插入行的一部分

  • 插入多行

  • 插入某些查询的结果

插入完整的行

INSERT INTO Customers
VALUES(NULL,
   'Pep E. LaPew',
   '100 Main Street',
   'Los Angles',
   '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语句填充所有列(与前面的一样),但以一种不同的次序填充。
#因为给出了列名,所以插入结果仍然正确:
INSERT INTO customers(cust_name,
  cust_contact,
  cust_email,
  cust_address,
  cust_city,
  cust_state,
  cust_zip,
  cust_country)
VALUES('Pep E. LaPew',
   NULL,
   NULL,
   '100 Main Street',
   'Los Angles',
   'CA',
   '90046',
   'USA');

不管哪种INSSERT语法,都必须给出VALUES的正确数目,如果不提供列名,则必须给每个表提供一个值。

如果提供列名,则必须对每个列出的列值给出一个值。

列名被明确列出时,可以省略列,如果表的定义允许则可以省略列

该列定义为允许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. Martian',
   '42 Galaxy Way'
   'New York',
   'NY',
   '11213',
   '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. Martian',
   '42 Galaxy Way'
   'New York',
   'NY',
   '11213',
   'USA');
?
#单条INSERT语句有多组值,每组值用一对圆括号括起来,用逗号分隔。

插入检索出的数据

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;

第二十章:更新和删除数据

更新数据

UPDATE

  • 更新表中特定行

  • 更新表中所有行 例:客户10005更新电子邮件

UPDATE customers
SET cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;

例:更新多个列

UPDARTE customers
SET cust_name = 'The Fudds',
cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;

在更新多个列时,只需要使用单个SET命令,每个“列=值”对之间 用逗号分隔(最后一列之后不用逗号)。在此例子中,更新客户10005的cust_name和cust_email列。

IGNORE关键字:如果用UPDATE语句更新多行,并且在更新这些 行中的一行或多行时出一个现错误,则整个UPDATE操作被取消 (错误发生前更新的所有行被恢复到它们原来的值)。为即使是发生错误,也继续进行更新,可使用IGNORE关键字,如下所示:UPDATE IGNORE customers…

为了删除某列的值,可以设置为NULL

UPDATE customers
SET cust_email = NULL
WHERE cust_id = 10005;

删除数据

使用DELETE语句

  • 从表中删除特定的行

  • 从表中删除所有的行

DELETE FROM customers
WHERE cust_id = 10006;

更新和删除的指导原则

下面是许多SQL程序员使用UPDATEDELETE时所遵循的习惯。

  • 除非确实打算更新和删除每一行,否则绝对不要使用不带WHERE子句的UPDATE或DELETE语句。

  • 保证每个表都有主键,尽可能像WHERE子句那样使用它(可以指定各主键、多个值或值的范围)。

  • 在对UPDATE或DELETE语句使用WHERE子句前,应该先用SELECT进行测试,保证它过滤的是正确的记录,以防编写的WHERE子句不正确。

  • 使用强制实施引用完整性的数据库,这样MySQL将不允许删除具有与其他表相关联的数据的行。

 

参考文章:《mysql必知必会》

https://blog.csdn.net/jankin6/article/details/119540143?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165518333516782425165452%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165518333516782425165452&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-119540143-null-null.142^v14^pc_search_result_control_group,157^v14^control&utm_term=mysql%E5%BF%85%E7%9F%A5%E5%BF%85%E4%BC%9A&spm=1018.2226.3001.4187