|
关于SQL的CRUD操作是很重要的,有些公司面试的时候会要求我们写一些SQL,我上次面试字节的时候就遇到了(手动狗头)。
在我们的超市项目中,我们给用户设计好了一个数据库demo.goodsmaster,定义好了里面的字段以及各种约束,如下:
mysql> desc demo.goodsmaster;
+---------------+--------------+------+-----+---------+--+
| Field | Type | Null | Key | Default |Extra |
+---------------+------------+------+-----+---------+------------+
| itemnumber | int | NO | PRI | NULL |auto_increment |
| barcode | text | NO | | NULL | |
| goodsname | text | NO | | NULL | |
| specification | text | YES | | NULL | |
| unit | text | YES | | NULL | |
| price | decimal(10,2)| NO | | NULL | |
+---------------+------------+------+-----+---------+----------------+
6 rows in set (0.02 sec)
OK,下面我们对这张表进行操作。
首先添加数据的语法结构如下:
insert into 表名 [(字段名 [,字段名] ...)] values (值的列表);
这里的’[ ]'表示里面的内容可选,也就是说,根据MySQL的语法要求,写不写都可以。
添加数据分为两种情况:插入数据记录和插入查询结果。下面进行分别介绍:
MySQL支持的数据插入操作十分灵活,你既可以通过给表里面所有的字段赋值,完整的插入一条数据记录,也可以在插入记录的时候,只给部分字段赋值。
还是上面的demo.goodsmaster表,其中包括了itemnumber, barcode, goodsname, specification, unit 和 price共6个字段。
我想要插入一条数据记录,其中包括了所有字段的值,就可以这样操作:
insert into demo.goodsmaster
(itemnumber, barcode, goodsname, specification, unit, price)
values (4, '0003', '尺子', '三角形', '把', 5);
运行这条SQL,然后对数据表进行查询:
mysql> select *
-> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 4 | 0003 | 尺子 | 三角型 | 把 | 5.00 |
+------------+---------+-----------+---------------+------+-------+
1 row in set (0.01 sec)
那如果我想插入一条记录,但是只给部分字段赋值,可以不?
比如说,客户有个商品,需要马上上线销售,目前只知道条码、名称和价格,其他的信息暂不录入,等之后再补,可以实现吗?
我们来尝试只给3个字段赋值,看看实际操作可以吗?
insert into demo.goodsmaster
(
-- 这里只给3个字段赋值,itemnumber、specification、unit不赋值
barcode,
goodsname,
price
)
VALUES
(
'0004',
'测试',
10
);
运行这条SQL语句,我们来查询表的数据,就会发现是可以的。
mysql> select *
-> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 4 | 0003 | 尺子 | 三角型 | 把 | 5.00 |
| 5 | 0004 | 测试 | NULL | NULL | 10.00 |
+------------+---------+-----------+---------------+------+-------+
2 rows in set (0.00 sec)
我们之所以能够在插入一条数据记录的时候,只给部分字段赋值,原因在于我们对字段的定义方式。
那字段是怎么定义的呢,我们来查看一下表的结构,看看各个字段的定义:
mysql> desc demo.goodsmaster;
+---------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+----------------+
| itemnumber | int | NO | PRI | NULL | auto_increment |
| barcode | text | NO | | NULL | |
| goodsname | text | NO | | NULL | |
| specification | text | YES | | NULL | |
| unit | text | YES | | NULL | |
| price | decimal(10,2) | NO | | NULL | |
+---------------+---------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
可以看到,我们刚刚在插入数据的时候没有明确赋值的3个字段,都有着各自的特点。
specification和unit都可以是空值,而itemnumber则定义了自增约束。
我们在插入一条数据记录的时候,必须要考虑字段约束的3种情况。
如果我们违反了字段的约束限制,会出现什么情况呢?
比如说,我们尝试把表demo.goodsmaster的字段specification改为不能为空:
alter table demo.goodsmaster
modify specification text not null;
运行这个 SQL 语句,系统会提示错误,原因就是我们刚才部分插入了一条数据记录,没有给字段“specification”赋值,这跟我们给字段“specification”添加非空约束的操作冲突了。
因此我们需要删除表中spcification值为空的数据记录,然后再修改字段约束:
delete from demo.goodsmaster
where itemnumber=5;
删除数据记录之后,在运行上面的语句,给字段specification添加非空约束,就成功了。
现在我们来验证一下非空约束。我们尝试部分插入一条数据记录,不给字段specification赋值:
insert into demo.goodsmaster
(barcode, goodsname, price)
values ('0004', '测试', 10);
运行这个SQL语句,MySQL会报错,提示字段specification没有默认值。也就是说,这个字段不能为空,如果插入数据时不给它赋值,就必须给它一个默认值。
现在我们清楚了,部分插入一条数据记录是可以的,但前提是,没有赋值的字段,一定要让MySQL知道如何处理,比如可以为空、有默认值,或者是自增约束字段,等等,否则,MySQL会提示错误。
在实际工作中呢,一次只插入一条数据,有时候会不够用。
所以接下来我们来讲解MySQL中的另外一种数据插入操作:把查询结果插入到数据表中。
MySQL支持把查询的结果插入到数据表中,我们可以指定字段,甚至是数值,插入到数据表中。语法结构如下:
insert into 表名 (字段名)
select 字段名或值
from 表名
where 条件
好了,添加数据的操作就讲完了,现在我们知道了,我们给一张数据表插入一条数据记录的时候,可以给所有的字段赋值,也可以给部分字段赋值,这取决于字段的定义。
如果字段不能为空并且没有默认值,就必须赋值。另外,我们还可以通过把一个查询结果插入数据表中的方式,提高添加数据的效率。
数据删除的语法很简答,如下:
delete from 表名
where 条件
如果我们现在想把刚才用过的表 demo.goodsmaster 里的内容清理一下,删除全部数据,可以通过下面的 SQL 语句来实现:
delete from demo.goodsmaster;
这里给出一个建议是:我们要习惯删除数据的时候,添加条件语句where,防止误操作。
假如我们的数据表 demo.goodsmaster 中有如下数据记录:
mysql> select *
-> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 4 | 0003 | 尺子 | 三角型 | 把 | 5.00 |
| 5 | 0004 | 测试 | NULL | NULL | 10.00 |
+------------+---------+-----------+---------------+------+-------+
2 rows in set (0.00 sec)
如果我们要删除表中所有数据,可以这样写:
delete from demo.goodsmaster where itemnumber > 1;
MySQL修改数据的语法:
update 表名
set 字段名=值
where 条件
注意:不要修改主键字段的值,因为主键是数据记录的唯一标识,如果修改了主键的值,就有可能会破坏数据的完整性。
我们来看看查询语句的语法结构:
select *|字段列表
from 数据源
where 条件
group by 字段
having 条件
order by 字段
limit 起始点,行数
在这些字段中,select、where、group by和having 比较好理解,我们只需要知道它们的含义就行了:
from、order by和 limit相对来说比较复杂,需要注意的地方比较多,请接着看:
from关键字标识查询的数据源。我们现在只学习了单个数据库,后面我们在学习关联表的时候,from关键字的后面会跟上更加复杂的数据表联接。
有一点需要注意的是,数据源不一定是表哦,也可以是一个查询的结果。比如:
红色框里的部分叫做派生表(derived table),或者子查询(subquery),意思是我们把一个查询结果数据集当做一个虚拟的数据表来看待。
MySQL中规定,必须要用AS关键字给这个派生表起一个别名。也就是上图的‘a’.
ORDER BY 的作用,是告诉 MySQL,查询结果如何排序。ASC 表示升序,DESC 表示降序。
举个简单的小例子,带你看看 ORDER BY 是怎么使用的(这里我们仍然假设字段“specification”和“unit”允许为空)。我们向表 demo.goodsmaster 中插入 2 条数据:
insert into demo.goodsmaster
(
barcode,
goodsname,
price
)
values
(
'0003',
'尺子1',
15
);
insert into demo.goodsmaster
(
barcode,
goodsname,
price
)
values
(
'0004',
'测试1',
20
);
如果我们不控制查询结果的顺序,就会得到这样的结果:
mysql> select *
-> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 4 | 0003 | 尺子 | 三角型 | 把 | 5.00 |
| 5 | 0004 | 测试 | NULL | NULL | 10.00 |
| 6 | 0003 | 尺子1 | NULL | NULL | 15.00 |
| 7 | 0004 | 测试1 | NULL | NULL | 20.00 |
+------------+---------+-----------+---------------+------+-------+
4 rows in set (0.00 sec)
如果我们使用 ORDER BY 对查询结果进行控制,结果就不一样了:
mysql> select *
-> from demo.goodsmaster
-> order by barcode asc, price desc;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 6 | 0003 | 尺子1 | NULL | NULL | 15.00 |
| 4 | 0003 | 尺子 | 三角型 | 把 | 5.00 |
| 7 | 0004 | 测试1 | NULL | NULL | 20.00 |
| 5 | 0004 | 测试 | NULL | NULL | 10.00 |
+------------+---------+-----------+---------------+------+-------+
4 rows in set (0.00 sec)
可以看到,查询结果会先按照字段 barcode 的升序排序,相同 barcode 里面的字段,按照 price 的降序排序。
LIMIT 的作用是告诉 MySQL 只显示部分查询的结果。比如,现在我们的数据表 demo.goodsmaster 中有 4 条数据,我们只想要显示第 2、3 条数据,就可以用 LIMIT 关键字来实现:
mysql> select *
-> from demo.goodsmaster
-> limit 1,2;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 5 | 0004 | 测试 | NULL | NULL | 10.00 |
| 6 | 0003 | 尺子1 | NULL | NULL | 15.00 |
+------------+---------+-----------+---------------+------+-------+
2 rows in set (0.00 sec)
这里的“LIMIT 1,2”中,“1”表示起始位置,MySQL 中,起始位置的起点是 0,1 表示从第 2 条记录开始;“2”表示 2 条数据。因此,“LIMIT 1,2”就表示从第 2 条数据开始,显示 2 条数据,也就是显示了第 2、3 条数据。
最后再补充一点,如果我们把查询的结果插入到表中时,导致主键约束或者唯一性约束被破坏了,就可以用“on duplicate”关键字进行处理。这个关键字的作用是,告诉 MySQL,如果遇到重复的数据,该如何处理。
举个例子: 假设用户有 2 个各自独立的门店,分别有自己的系统。现在需要引入连锁经营的模式,把 2 个店用一套系统统一管理。那么首先遇到的问题就是,需要进行数据整合。下面我们就以商品信息表为例,来说明如何通过使用“on duplicate”关键字,把两个门店的商品信息数据整合到一起。
假设门店 A 的商品信息表是“demo.goodsmaster”,代码如下:
mysql> select *
-> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+------------+
| itemnumber | barcode | goodsname | specification | unit | salesprice |
+------------+---------+-----------+---------------+------+------------+
| 1 | 0001 | 书 | 16开 | 本 | 89.00 |
| 2 | 0002 | 笔 | 10支装 | 包 | 5.00 |
| 3 | 0003 | 橡皮 | NULL | 个 | 3.00 |
+------------+---------+-----------+---------------+------+------------+
3 rows in set (0.00 sec)
门店 B 的商品信息表是“demo.goodsmaster1”:
mysql> select *
-> from demo.goodsmaster1;
+------------+---------+-----------+---------------+------+------------+
| itemnumber | barcode | goodsname | specification | unit | salesprice |
+------------+---------+-----------+---------------+------+------------+
| 1 | 0001 | 教科书 | NULL | NULL | 89.00 |
| 4 | 0004 | 馒头 | | | 1.50 |
+------------+---------+-----------+---------------+------+------------+
2 rows in set (0.00 sec)
假设我们要把门店 B 的商品数据,插入到门店 A 的商品表中去,如果有重复的商品编号,就用门店 B 的条码,替换门店 A 的条码,用门店 B 的商品名称,替换门店 A 的商品名称;如果没有重复的编号,就直接把门店 B 的商品数据插入到门店 A 的商品表中。这个操作,就可以用下面的 SQL 语句实现:
insert into demo.goodsmaster
select * from demo.goodsmaster as a
on duplicate key update barcode = a.barcode, goodsname = a.goodsname;
运行结果如下:
-- 运行结果如下
mysql> select *
-> from demo.goodsmaster;
+------------+---------+-----------+---------------+------+------------+
| itemnumber | barcode | goodsname | specification | unit | salesprice |
+------------+---------+-----------+---------------+------+------------+
| 1 | 0001 | 教科书 | 16开 | 本 | 89.00 |
| 2 | 0002 | 笔 | 10支装 | 包 | 5.00 |
| 3 | 0003 | 橡皮 | NULL | 个 | 3.00 |
| 4 | 0004 | 馒头 | | | 1.50 |
+------------+---------+-----------+---------------+------+------------+
4 rows in set (0.00 sec)