MySQL 中最基本也是最重要的是 操作数据表中的记录 ,也就是对数据表中的记录进行增删改查操作。
INSERT
添加记录的三种方式:
1. INSERT ... VALUES ...
INSERT [INTO] table_name [(column_name,...)] {VALUES|VALUE} ({expr(表达式)|DEFAULT(默认值)},...),(...),...;
# 若省略列名则所有列要依次赋值
# 对于自动编号的字段,插入“NULL”或“DEFAULT”系统将自动依次递增编号;
# 对于有默认值的字段,可以插入“DEFAULT”表示使用默认值;
# 可同时插入多条记录,多条记录括号间用逗号“,”隔开.
2. INSERT ... SET ...
INSERT INTO tbl_name SET col_name = {expr | DEFAULT},...
# 该语句与第一种方法的区别是该语句可以使用子查询(SubQuery)
# 该语句一次只能插入一条记录;
3. INSERT ... SELECT ...
INSERT INTO tbl_name[(col_name)] SELECT...
# eg: INSERT INTO tb1(name) SELECT name FROM tb2 WHERE id > 10;
后续…
DELETE
删除记录有两种方法,单表删除与多表删除
1. 单表删除
DELETE FROM 表名 [WHERE where_condition]
# 如果不写where语句限定条件,那么就会删除所有数据
# 如果删除了某条记录,添加表单时,具有AUTO_INCREMENT的字段其值会在现有最大值的基础上顺延下去
2. 多表删除
略
# eg: DELETE t1 FROM tdb_goods AS t1 LEFT JOIN (SELECT goods_id,goods_name FROM tdb_goods GROUP BY goods_name HAVING count(goods_name) >= 2 ) AS t2 ON t1.goods_name = t2.goods_name WHERE t1.goods_id > t2.goods_id;
后续…
UPDATE
修改记录也有两种方法,单表更新与链表更新
1. 单表更新
UPDATE table_reference SET col_name1={expr1|DEFAULT} [,col_name2={expr2|DEFAULT}]... [WHERE where_condition]
# 如果不写where语句限定条件,那么就会更新所有数据
2. 链表更新
略
# eg:UPDATE tdb_goods INNER JOIN tdb_goods_cates ON goods_cate = cate_name SET goods_cate = cate_id ;
SELECT
80% 我们都是在使用 select 操作语句
SELECT [ALL | DISTINCT] column1[,column2]
FROM table1[,table2]
[WHERE "conditions"]
[GROUP BY "column-list"]
[HAVING "conditions]
[ORDER BY "column-list" [ASC | DESC] ]
1. select_expr
# 版本号
SELECT VERSION();
# 表达式
SELECT 1+1;
# 上面的栗子说明,select 不一定需要添加数据表,只要表达式即可完成查询动作!
2. [AS]
SELECT column_name AS alias_name FROM table_name
# [AS] 可以省略,但不建议省略,联表查询时别名很重要
3. WHERE
WHERE 列 运算符 值
4 . GROUP BY
[GROUP BY{col_name|position} [ASC|DESC],...]
# 对查询结果进行分组,分组的条件字段,字段值相同的就是一组
5. HAVING
[HAVING where_condition]
# 分组条件 or1 : HAVING后的字段出现在SELECT所查询的字段中;
# 分组条件 or2 : 聚合函数
6. ORDER BY
[ORDER BY [col_name | expr | position } [ASC|DESC],...]
# 多个条件时,如果第一个条件 还不足排序 就拿下一个条件在原来的基础上在进行一次排序,若第一个字段已满足排序,则忽略后面的字段
7. LIMIT
[LIMIT {[offset,]row_count|row_count OFFSET offset}]
# offset:偏移量,从 零 开始
# row_count:返回结果的数目
子查询
子查询简介
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
SELECT * FROM t1 … 被称为外查询 Outer Query ,(SELECT column1 FROM t2); 被称为子查询 Sub Query;
- 子查询指嵌套在【查询内部】,且必须始终出现在【圆括号内】
- 子查询可以包含多个关键字或者条件,如DISTINCT,GROUP BY,ORDER BY,LIMIT,函数等
- 子查询的外层查询可以是:【SELECT,INSERT,UPDATE,SET或DO】
- 子查询可以返回值:标量、一行、一列或者子查询。
1 . 由比较运算符引发的子查询
1.1 使用子查询获取商品价格大于平均价格的商品,并且按价格降序排序:
SELECT goods_id,goods_name,goods_price FROM tdb_goods
WHERE goods_price > (SELECT ROUND(AVG(goods_price),2) AS avg_price FROM tdb_goods)
ORDER BY goods_price DESC;
# ROUND 四舍五入取值,AVG 平均值;
1.2 查询价格大于或等于”超级本”价格的商品,并且按价格降序排列,子查询 #SELECT goods_price FROM tdb_goods WHERE goods_cate = ‘超级本’ 返回结果有 3 个结果,如果仅使用 > ,无法确定是大于 3 个结果值的最大值还是大于 3 个结果值的最小值,这里需要引入 ANY/SOME 和 ALL 的运算;
SELECT goods_id,goods_name,goods_price FROM tdb_goods
WHERE goods_price = ANY(SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本')
ORDER BY goods_price DESC;
# ANY/SOME 是任何一个符合条件,ALL是全部符合条件;
2 . 由 [ NOT ] IN 引发的子查询
[NOT] IN引起的子查询:字段 [NOT] IN(value1,vaule2…),可查询字段是否在括号内的值中存在,并返回一个布尔值,也因此可用于子查询,因为select也会返回一个结果集。
SELECT goods_id,goods_name,goods_price FROM tdb_goods
WHERE goods_price IN (SELECT goods_price FROM tdb_goods WHERE goods_cate = ‘超级本’)
ORDER BY goods_price DESC;
# ANY 或 SOME 等价于 IN,NOT IN 相当于 != ALL 或者 <> ALL —— 不等于、不包含。
3 . [NOT] EXISTS引起的子查询
如果子查询返回至少一行数据,则exists 返回 true,反之 返回 false
where [NOT] EXISTS(select ….)类似于where 字段 [NOT] IN(select ….),但侧重点不一样,EXISTS侧重于select是否返回了语句,如果返回了数据,则该行就是true;
SELECT * FROM tdb_goods WHERE EXISTS(SELECT goods_id FROM test WHERE goods_id = t_id)
4 . INSERT … SELECT ...
将分组结果写入到 tdb_goods_cates 数据表
INSERT tdb_goods_cates (cate_name) SELECT goods_cate FROM tdb_goods GROUP BY goods_cate;
5. 多表更新
UPDATE 表名1 {[INNER | CROSS ] JOIN|{LEFT|RIGHT} [OUTER] JOIN} 对应表名2 ON 对应条件 SET 字段名1={expr1 | DEFAULT} [,字段名2={expr2 | DEFAULT}]... [WHERE where_condition]
更新过程:
- 先确定连接关系,如表1 INNER JOIN 表2,
- 然再确定连接条件,如ON 表1.name=表2.name
- 确定要把表1的字段改成表2的哪个字段,SET 字段=…,其中①和②是表的连接
通过tdb_goods_cates数据表来更新tdb_goods表
UPDATE tdb_goods INNER JOIN tdb_goods_cates ON goods_cate = cate_name
SET goods_cate = cate_id ;
多表更新之一步到位
建表、查询、写入三合一:CREATE和SELECT语句结合,需注意,select返回的字段,如果在CREATE的表中不存在,那么就会自动创建该字段并写入信息,而如果已有该字段,就覆盖并写入该字段信息(相当于改变该字段的位置),如表中有a,b,c字段,如果select b,d,那么表中字段顺序会变成acbd,并且bd被写入select的值。
如:通过CREATE…SELECT来创建数据表并且同时写入记录
CREATE TABLE tdb_goods_brands (
brand_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
brand_name VARCHAR(40) NOT NULL
)
SELECT brand_name FROM tdb_goods GROUP BY brand_name;
使用新表数据更新商品表数据:
UPDATE tdb_goods AS g INNER JOIN tdb_goods_brands AS b ON g.brand_name = b.brand_name
SET g.brand_name = b.brand_id;
注意:这里必须使用到别名,因为两个表的字段名称相同;
join 连接
SQL 在 select 、多表跟新、多表删除时支持 JOIN 操作!连接需要考虑的是参照关系,谁参照谁这个就非常重要!
类型:
- INNER JOIN 内连接,只显示符合连接条件的记录
- RIGHT JOIN 右表全部加左表交集,没有项为NULL
- LEFT JOIN 构建临时表时会先创建所有表1的值,再把符合条件的表2的行并入
查询所有商品的详细信息为例:
内连接(JOIN | CROSS JOIN | INNER JOIN)
SELECT goods_id,goods_name,cate_name,brand_name,goods_price FROM tdb_goods AS g
INNER JOIN tdb_goods_cates AS c ON g.cate_id = c.cate_id
INNER JOIN tdb_goods_brands AS b ON g.brand_id = b.brand_id\G;
左外连接(LEFT JOIN)
SELECT goods_id,goods_name,cate_name,brand_name,goods_price FROM tdb_goods AS g
LEFT JOIN tdb_goods_cates AS c ON g.cate_id = c.cate_id
LEFT JOIN tdb_goods_brands AS b ON g.brand_id = b.brand_id\G;
右外连接(RIGHT JOIN)
SELECT goods_id,goods_name,cate_name,brand_name,goods_price FROM tdb_goods AS g
RIGHT JOIN tdb_goods_cates AS c ON g.cate_id = c.cate_id
RIGHT JOIN tdb_goods_brands AS b ON g.brand_id = b.brand_id\G;
# 这里使使用ON关键字来设定连接条件,也可以使用WHERE来代替,通常使用ON关键字来设定连接条件,使用WHERE关键字进行结果集记录的过滤。
无限分类的数据表设计
CREATE TABLE tdb_goods_types(
type_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
type_name VARCHAR(20) NOT NULL,
parent_id SMALLINT UNSIGNED NOT NULL DEFAULT 0
);
— 查找所有分类及其父类
SELECT s.type_id,s.type_name,p.type_name
FROM tdb_goods_types AS s
LEFT JOIN tdb_goods_types AS p
ON s.parent_id = p.type_id;
— 查找所有分类及其子类
SELECT s.type_id,s.type_name,p.type_name
FROM tdb_goods_types AS s
LEFT JOIN tdb_goods_types AS p
ON s.parent_id = p.type_id;
— 查找所有分类及其子类的数目
SELECT p.type_id,p.type_name,count(s.type_name) AS children_count
FROM tdb_goods_types AS p
LEFT JOIN tdb_goods_types AS s ON s.parent_id = p.type_id
GROUP BY p.type_name
ORDER BY p.type_id;
— 为tdb_goods_types添加child_count字段
ALTER TABLE tdb_goods_types
ADD child_count MEDIUMINT UNSIGNED NOT NULL DEFAULT 0;
— INSERT … SELECT实现复制
INSERT tdb_goods(goods_name,cate_id,brand_id)
SELECT goods_name,cate_id,brand_id
FROM tdb_goods
WHERE goods_id IN (19,20);
— 查找重复记录
SELECT goods_id,goods_name FROM tdb_goods
GROUP BY goods_name
HAVING count(goods_name) >= 2;
— 删除重复记录
DELETE t1 FROM tdb_goods AS t1
LEFT JOIN (SELECT goods_id,goods_name FROM tdb_goods GROUP BY goods_name HAVING count(goods_name) >= 2 ) AS t2
ON t1.goods_name = t2.goods_name WHERE t1.goods_id > t2.goods_id;