聚合查询的列中,只能放入分组的列。
使用多个列进行分组
例如,我们想统计各班的男生和女生人数:
-- 按class_id, gender分组:
SELECT class_id, gender, COUNT(*) num FROM students GROUP BY class_id, gender;
查询练习:
-- 查出每个班级的平均分,结果集应当有3条记录:
SELECT class_id, AVG(score) avg_score FROM students GROUP BY class_id;
-- 查出每个班级的平均分,结果集应当有6条记录:
SELECT class_id, gender, AVG(score) avg_sco FROM students GROUP BY class_id, gender;
-- 查出每个班级的平均分,并按照从高到低排序,结果集应当有6条记录,:
SELECT class_id, gender, AVG(score) avg_sco FROM students GROUP BY class_id, gender ORDER BY avg_sco DESC;
-- 配合WHERE语句
SELECT class_id, AVG(score) avg_sco_boys FROM students WHERE gender=‘M‘ GROUP BY class_id;
4.7 多表查询
查询多张表的语法是:SELECT * FROM <表1> <表2> 。
-- FROM students, classes:
SELECT * FROM students, classes;
一次查询两个表的数据,查询的结果也是一个二维表,它是students 表和classes 表的“乘积”,即students 表的每一行与classes 表的每一行都两两拼在一起返回。结果集的列数是students 表和classes 表的列数之和,行数是students 表和classes 表的行数之积。
这种多表查询又称笛卡尔查询,
SELECT
s.id sid,
s.name,
s.gender,
s.score,
c.id cid,
c.name cname
FROM students s, classes c
WHERE s.gender = ‘M‘ AND c.id = 1;
例子:
查询每个班男女生分别有多少人,并且列名班级是从 classes中取出的
SELECT
c.name ‘班级‘,
s.gender ‘性别‘,
COUNT(s.gender) ‘人数‘
FROM students s, classes c
WHERE c.id = s.class_id
GROUP BY s.class_id, s.gender;
4.8 连接查询
连接查询对多个表进行JOIN运算,简单地说,就是先确定一个主表作为结果集,然后,把其他表的行有选择性地“连接”在主表结果集上。
四种链接方式
-
INNER JOIN 只返回同时存在于两张表的行数据
-
RIGHT OUTER JOIN 返回右表都存在的行。
如果某一行仅在右表存在,那么结果集就会以NULL 填充剩下的字段。
-
LEFT OUTER JOIN则返回左表都存在的行。
-
FULL OUTER JOIN,它会把两张表的所有记录全部选择出来,并且,自动把对方不存在的列填充为NULL
-
内连接——INNER JOIN
INNER JOIN只返回同时存在于两张表的行数据
例子:
从students表中列出所有学生
根据classes表中的班级 name列,连接到students主表中去
students表中的班级和classes中的name列的对应关系是根据
s.class_id = c.id
来保证的
-- 选出所有学生,同时返回班级名称
SELECT s.id, s.name, s.class_id, c.name class_name, s.gender, s.score
FROM students s
INNER JOIN classes c
ON s.class_id = c.id;
注意INNER JOIN查询的写法是:
- 先确定主表,仍然使用
FROM <表1> 的语法;
- 再确定需要连接的表,使用
INNER JOIN <表2> 的语法;
- 然后确定连接条件,使用
ON <条件...> ,这里的条件是s.class_id = c.id ,表示students 表的class_id 列与classes 表的id 列相同的行需要连接;
- 可选:加上
WHERE 子句、ORDER BY 等子句。
使用别名不是必须的,但可以更好地简化查询语句。
如何选用
假设查询语句是:
SELECT ... FROM tableA ??? JOIN tableB ON tableA.column1 = tableB.column2;
小结
- JOIN查询需要先确定主表,然后把另一个表的数据“附加”到结果集上;
- INNER JOIN是最常用的一种JOIN查询,
它的语法是SELECT ... FROM <表1> INNER JOIN <表2> ON <条件...> ;
- JOIN查询仍然可以使用
WHERE 条件和ORDER BY 排序。
5. 修改数据
关系数据库的基本操作就是增删改查
对于增、删、改,对应的SQL语句分别是:
- INSERT:插入新记录;
- UPDATE:更新已有记录;
- DELETE:删除已有记录。
5.1 INSERT
INSERT 语句的基本语法是:
INSERT INTO <表名> (字段1, 字段2, ...) VALUES (值1, 值2, ...);
例如,我们向students 表插入一条新记录,先列举出需要插入的字段名称,然后在VALUES 子句中依次写出对应字段的值:
-- 添加一条新记录
INSERT INTO students (class_id, name, gender, score) VALUES (2, ‘大牛‘, ‘M‘, 80);
-- 查询并观察结果:
SELECT * FROM students;
- 一次添加多条记录
只需要在VALUES 子句中指定多个记录值,每个记录是由(...) 包含的一组值
INSERT INTO students (class_id, name, gender, score) VALUES
(1, ‘大宝‘, ‘M‘, 87),
(2, ‘二宝‘, ‘M‘, 81);
SELECT * FROM students;
5.2 UPDATE
UPDATE 语句的基本语法是:
UPDATE <表名> SET 字段1=值1, 字段2=值2, ... WHERE ...;
UPDATE 语句会返回更新的行数以及WHERE 条件匹配的行数。
例如,我们想更新students 表id=1 的记录的name 和score 这两个字段,
先写出UPDATE students SET name=‘大牛‘, score=66 ,
然后在WHERE 子句中写出需要更新的行的筛选条件id=1 :
-- 更新id=1的记录
UPDATE students SET name=‘大牛‘, score=66 WHERE id=1;
-- 查询并观察结果:
SELECT * FROM students WHERE id=1;
UPDATE students SET name=‘小牛‘, score=77 WHERE id>=5 AND id<=7;
-- 查询并观察结果:
SELECT * FROM students;
UPDATE students SET score=score+10 WHERE score<80;
-- 查询并观察结果:
SELECT * FROM students;
如果WHERE 条件没有匹配到任何记录,UPDATE 语句不会报错,也不会有任何记录被更新。
特别注意
UPDATE 语句可以没有WHERE 条件,例如:
UPDATE students SET score=60;
这时,整个表的所有记录都会被更新。所以,在执行UPDATE 语句时要非常小心,最好先用SELECT 语句来测试WHERE 条件是否筛选出了期望的记录集,然后再用UPDATE 更新。
5.3 DELET
DELETE 语句也会返回删除的行数以及WHERE 条件匹配的行数
DELETE 语句的基本语法是:
DELETE FROM <表名> WHERE ...;
DELETE FROM students WHERE id=1;
DELETE FROM students WHERE id>=5 AND id<=7;
-- 查询并观察结果:
SELECT * FROM students;
如果WHERE 条件没有匹配到任何记录,DELETE 语句不会报错,也不会有任何记录被删除。
特别注意
别小心的是,和UPDATE 类似,不带WHERE 条件的DELETE 语句会删除整个表的数据:
DELETE FROM students;
6.MySQL
MySQL Server |
真正的MySQL服务器 |
可执行程序是mysqld |
MySQL Client程序 |
一个命令行客户端,可以通过MySQL Client登录MySQL |
可执行程序是mysql |
MySQL Client和MySQL Server的关系如下:
小结
命令行程序mysql 实际上是MySQL客户端,真正的MySQL服务器程序是mysqld ,在后台运行。
6.1 管理MySQL
很多时候,通过SSH远程连接时,只能使用SQL命令,所以,了解并掌握常用的SQL管理操作是必须的。
数据库:
表:
6.2 实用SQL语句
插入或替换
如果我们希望插入一条新记录(INSERT),但如果记录已经存在,就先删除原记录,再插入新记录。此时,可以使用REPLACE 语句,这样就不必先查询,再决定是否先删除再插入:
REPLACE INTO students (id, class_id, name, gender, score) VALUES (1, 1, ‘小明‘, ‘F‘, 99);
若id=1 的记录不存在,REPLACE 语句将插入新记录,否则,当前id=1 的记录将被删除,然后再插入新记录。
插入或更新
如果我们希望插入一条新记录(INSERT),但如果记录已经存在,就更新该记录,此时,可以使用INSERT INTO ... ON DUPLICATE KEY UPDATE ... 语句:
INSERT INTO students (id, class_id, name, gender, score) VALUES (1, 1, ‘小明‘, ‘F‘, 99) ON DUPLICATE KEY UPDATE name=‘小明‘, gender=‘F‘, score=99;
若id=1 的记录不存在,INSERT 语句将插入新记录,否则,当前id=1 的记录将被更新,更新的字段由UPDATE 指定。
插入或忽略
如果我们希望插入一条新记录(INSERT),但如果记录已经存在,就啥事也不干直接忽略,此时,可以使用INSERT IGNORE INTO ... 语句:
INSERT IGNORE INTO students (id, class_id, name, gender, score) VALUES (1, 1, ‘小明‘, ‘F‘, 99);
若id=1 的记录不存在,INSERT 语句将插入新记录,否则,不执行任何操作。
快照
如果想要对一个表进行快照,即复制一份当前表的数据到一个新表,可以结合CREATE TABLE 和SELECT :
-- 对class_id=1的记录进行快照,并存储为新表students_of_class1:
CREATE TABLE students_of_class1 SELECT * FROM students WHERE class_id=1;
新创建的表结构和SELECT 使用的表结构完全一致。
写入查询结果集
如果查询结果集需要写入到表中,可以结合INSERT 和SELECT ,将SELECT 语句的结果集直接插入到指定表中。
例如,创建一个统计成绩的表statistics ,记录各班的平均成绩:
CREATE TABLE statistics (
id BIGINT NOT NULL AUTO_INCREMENT,
class_id BIGINT NOT NULL,
average DOUBLE NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO statistics (class_id, average) SELECT class_id, AVG(score) FROM students GROUP BY class_id;
确保INSERT 语句的列和SELECT 语句的列能一一对应,就可以在statistics 表中直接保存查询的结果:
强制使用指定索引
在查询的时候,数据库系统会自动分析查询语句,并选择一个最合适的索引。但是很多时候,数据库系统的查询优化器并不一定总是能使用最优索引。如果我们知道如何选择索引,可以使用FORCE INDEX 强制查询使用指定的索引。例如:
> SELECT * FROM students FORCE INDEX (idx_class_id) WHERE class_id = 1 ORDER BY id DESC;
指定索引的前提是索引idx_class_id 必须存在。
7. 事务
把多条语句作为一个整体进行操作的功能,被称为数据库事务。
数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。如果事务失败,那么效果就和没有执行这些SQL一样,不会对数据库数据有任何改动。
数据库事务具有ACID这4个特性:
- A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
- C:Consistent,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;
- I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
- D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。
对于单条SQL语句,数据库系统自动将其作为一个事务执行,这种事务被称为隐式事务。
手动把多条SQL语句作为一个事务执行,
使用BEGIN 开启一个事务,使用COMMIT 提交一个事务,这种事务被称为显式事务,
例如,把上述的转账操作作为一个显式事务:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
多条SQL语句要想作为一个事务执行,就必须使用显式事务。
COMMIT 是指提交事务,即试图把事务内的所有SQL所做的修改永久保存。如果COMMIT 语句执行失败了,整个事务也会失败。
7.1 ROLLBACK
有些时候,我们希望主动让事务失败,这时,可以用ROLLBACK 回滚事务,整个事务会失败:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
ROLLBACK;
数据库事务是由数据库系统保证的,我们只需要根据业务逻辑使用它就可以。
提交事务,即确认DML的改动,使用commit;
回滚事务,即要回退掉之前的操作,使用rollback;
另外:如果不提交也不回滚,
执行的DML只是在当前会话有效,在其他会话是不生效的(不信你再重新打开一个连接窗口看看),
所以begin一开始,要么以commit结束,要么以rollback结束。
意思是,
在执行较大量的update或delete时,一定要用事务事务
可以在执行出错后,回滚到BEGIN语句还未开始的状态
例子:
SELECT * FROM statistics;
BEGIN;
UPDATE statistics SET average=average-60 WHERE id=1;
SELECT * FROM statistics;
UPDATE statistics SET ave=average-60 WHERE id=2;
ROLLBACK;
SELECT * FROM statistics;
执行结果:
2、3、4
5.SQL语句报错(或者自己进行了误操作想进行回滚)
6、7.执行回滚操作并显示回滚后的结果
隔离级别
对于两个并发执行的事务,如果涉及到操作同一条记录的时候,可能会发生问题。
因为并发操作会带来数据的不一致性,包括脏读、不可重复读、幻读等。数据库系统提供了隔离级别来让我们有针对性地选择事务的隔离级别,避免数据不一致的问题。
SQL标准定义了4种隔离级别,分别对应可能出现的数据不一致的情况:
Isolation Level |
脏读(Dirty Read) |
不可重复读 (Non Repeatable Read) |
幻读(Phantom Read) |
Read Uncommitted |
Yes |
Yes |
Yes |
Read Committed |
- |
Yes |
Yes |
Repeatable Read |
- |
- |
Yes |
Serializable |
- |
- |
- |
我们会依次介绍4种隔离级别的数据一致性问题。
默认隔离级别
如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。
7.2 Read Uncommitted(脏读)
在Read Uncommitted隔离级别下,一个事务可能读取到另一个事务更新但未提交的数据,这个数据有可能是脏数据。
准备好students 表的数据,该表仅一行记录:
mysql> select * from students;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
+----+-------+
1 row in set (0.00 sec)
然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:
时刻 |
事务A |
事务B |
1 |
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 |
BEGIN; |
BEGIN; |
3 |
UPDATE students SET name = ‘Bob‘ WHERE id = 1; |
|
4 |
|
SELECT * FROM students WHERE id = 1; |
5 |
ROLLBACK; |
|
6 |
|
SELECT * FROM students WHERE id = 1; |
7 |
|
COMMIT; |
当事务A执行完第3步时,它更新了id=1 的记录,但并未提交,
而事务B在第4步读取到的数据就是未提交的数据。
随后,事务A在第5步进行了回滚,事务B再次读取id=1 的记录,发现和上一次读取到的数据不一致,这就是脏读。
7.3 Read Committed(不可重复读)
在Read Committed隔离级别下,事务不可重复读同一条记录,因为很可能读到的结果不一致。
不可重复读(Non Repeatable Read)的问题是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,两次读取的数据可能不一致。
时刻 |
事务A |
事务B |
1 |
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 |
BEGIN; |
BEGIN; |
3 |
|
SELECT * FROM students WHERE id = 1; |
4 |
UPDATE students SET name = ‘Bob‘ WHERE id = 1; |
|
5 |
COMMIT; |
|
6 |
|
SELECT * FROM students WHERE id = 1; |
7 |
|
COMMIT; |
7.4 Repeatable Read(幻读)
在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。
幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。
students 表的数据:
mysql> select * from students;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
+----+-------+
1 row in set (0.00 sec)
然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:
时刻 |
事务A |
事务B |
1 |
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
2 |
BEGIN; |
BEGIN; |
3 |
|
SELECT * FROM students WHERE id = 99; |
4 |
INSERT INTO students (id, name) VALUES (99, ‘Bob‘); |
|
5 |
COMMIT; |
|
6 |
|
SELECT * FROM students WHERE id = 99; |
7 |
|
UPDATE students SET name = ‘Alice‘ WHERE id = 99; |
8 |
|
SELECT * FROM students WHERE id = 99; |
9 |
|
COMMIT; |
事务B在第3步第一次读取id=99 的记录时,读到的记录为空,说明不存在id=99 的记录。
随后,事务A在第4步插入了一条id=99 的记录并提交。
事务B在第6步再次读取id=99 的记录时,读到的记录仍然为空,
但是,事务B在第7步试图更新这条不存在的记录时,竟然成功了,
并且,事务B在第8步再次读取id=99 的记录时,记录出现了。
7.5 Serializable
Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。
虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。
8. SQL语句汇总
show databases;
show tables;
select * from students;
-- 基本查询
select * from classes;
-- 条件查询
select * from students where score >= 90;
select * from students where score >= 80 and gender=‘M‘;
select * from students where score >= 90 or gender=‘M‘;
select * from students where not class_id = 2;
-- 多个条件,使用括号指定先后顺序
select * from students where (score<80 or score>90) and gender = ‘M‘;
-- 投影查询
-- 让查询结果只包含指定的列(指定的字段)
select id, score, name from students;
-- 让结果集的列名与原表的列名不同
select id, score points, name from students;
select id, score points, name from students where gender=‘M‘;
-- 排序(对查询的结果进行排序)
-- 默认为升序排列(ASC)
select id, name, gender, score from students order by score;
select id, name, gender, score from students order by score desc;
-- 如果有相同列,再指定额外的排序字段
select id, name, gender, score from students order by score desc, gender;
-- 分页查询
-- 从结果集中“截取”出第M~N条记录
-- `LIMIT`总是设定为`pageSize`;
-- `OFFSET`计算公式为`pageSize * (pageIndex - 1)`。
SELECT
id, name, gender, score
FROM
students
ORDER BY score DESC , gender
limit 3 offset 0;
-- 聚合查询
-- 查询表的总行数
select count(*) from students;
-- 设置结果集的列名
select count(*) num from students;
-- 统计有多少男生
SELECT
COUNT(*) num_boys
FROM
students
WHERE
gender = ‘M‘;
-- 计算男生平均成绩
SELECT
AVG(score) avg_sco_boy
FROM
students
WHERE
gender = ‘M‘;
-- 计算总分页数量
-- 已知,设定每页3行,计算总的页数
-- (向上取整)
SELECT
CEILING(COUNT(*) / 3) total_pages
FROM
students;
-- 分组
-- 查询每个班分别有多少人
select class_id, count(*) class_num from students group by class_id;
-- 统计每个班 男生 和 女生 的数量
select class_id, gender, count(*) num from students group by class_id, gender;
-- 查出每个班级的平均分
select class_id, AVG(score) avg_score from students group by class_id;
-- 查找每个班 男女生分别的平均成绩
SELECT
class_id, gender, AVG(score) avg_score
FROM
students
GROUP BY class_id , gender;
-- 查找每个班男生的平均成绩,并按照降序排列结果集
SELECT
class_id, AVG(score) avg_score
FROM
students
WHERE
gender = ‘M‘
GROUP BY class_id
ORDER BY avg_score DESC;
--
-- 多表查询
--
SELECT
s.id sid, s.name, s.gender, s.score, c.id cid, c.name cname
FROM
students s,
classes c
WHERE
s.gender = ‘M‘ AND c.id = 1;
-- 查询每个班男女生分别有多少人,班级名称从classes中提取
SELECT
c.name ‘班级‘, s.gender ‘性别‘, COUNT(*) ‘人数‘
FROM
students s,
classes c
WHERE
c.id = s.class_id
GROUP BY s.class_id , s.gender
ORDER BY ‘班级‘, ‘人数‘;
--
-- 连接查询JOIN
--
-- 列出所有学生,并返回班级名称(要求students表中的class_id是在classes表中存在的)
SELECT
s.name ‘姓名‘, c.name ‘班级‘
FROM
students s
INNER JOIN
classes c ON s.class_id = c.id;
--
--
-- 修改数据(增、改、删)
--
--
-- 插入数据
-- 一次插入一条
insert into students ( class_id, name, gender, score ) value (2, ‘大牛‘, ‘M‘, 86);
select * from students;
-- 一次插入多条
insert into students ( class_id, name, gender, score )
value
(2, ‘大牛‘, ‘M‘, 86),
(3, ‘大大牛‘, ‘M‘, 96);
select * from students;
-- UODATE
-- 更新指定条件的记录,更新指定的字段
update students set name=‘小唐9646‘, score=96 where id=1;
select * from students where id=1;
-- 指定值,更新多条(满足条件的)
select * from students;
update students set name=‘测试新增‘, score=88 where id>=12 and id<=14;
select * from students;
update students set score = score+2 where id=1;
-- 删除Delect语句
-- 删除一条
delete from students where id=12;
select * from students;
-- 删除多条,搭配where语句
delete from students where id>=12 and id <= 14;
select * from students;
-- 设定为唯一索引约束
-- 例如,名字不能相同
-- (唯一约束,这种方式不添加索引)
alter table students add constraint unit_name unique(name);
select * from students;
-- 由于设置了name列的唯一约束限制,因此,不能插入重复名字的记录
insert into students (class_id, name, gender, score) value(1, ‘小红2‘, ‘F‘, 85);
select * from students;
-- SQL相关命令
show databases;
create database test_database;
use test_database;
show tables;
use test;
show tables;
-- 查看表的描述
desc students;
-- 查看表创建的时候的描述
show create table students;
-- 创建表
CREATE TABLE `students2` (
`id` bigint NOT NULL AUTO_INCREMENT,
`class_id` bigint NOT NULL,
`name` varchar(100) NOT NULL,
`gender` varchar(1) NOT NULL,
`score` int NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unit_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
-- 删除表
drop table students2;
-- 创建表
create table `tangg_students` (
`id` bigint not null auto_increment,
`class_id` bigint not null,
`name` varchar(100) not null,
`score` int not null,
primary key (`id`),
unique key `unit_name`(`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 在表中插入记录
insert into tangg_students (class_id, name, score) value (2, ‘1号‘, 88);
insert into tangg_students (class_id, name, score) value (1, ‘2号‘, 92), (3, ‘4号‘, 82), (1, ‘5号‘, 78);
select * from tangg_students;
desc tangg_students;
-- 修改表
-- 给表新增列
alter table tangg_students add column birth varchar(10) not null;
select * from tangg_students;
-- 修改列名
alter table tangg_students change column birth birthday varchar(20) not null;
select * from tangg_students;
-- 删除列
alter table tangg_students drop column birthday;
select * from tangg_students;
--
-- 使用SQL语句
--
-- 插入或者替换
-- 如果记录已经存在,就先删除原记录,再插入新记录
select * from students;
replace into students (id, class_id, name, gender, score) value (16, 1, ‘小小唐‘, ‘F‘, 89);
select * from students;
-- 若`id=16`的记录不存在,`REPLACE`语句将插入新记录,否则,当前`id=1`的记录将被删除,然后再插入新记录。
-- 插入或者更新
-- 如果记录已经存在,就更新该记录,如果不存在就插入新纪录
select * from students;
insert into students (id, class_id, name, gender, score) value (1, 1, ‘唐广同学‘, ‘M‘, 92) on duplicate key update name= ‘小唐同学‘, score=93;
select * from students;
-- 快照
-- 复制当前表的数据到一个新表
-- 将一班的所有记录复制到新表
create table students_class_1 select * from students where class_id = 1;
select * from students_class_1;
desc students_class_1;
show create table students_class_1;
-- 将查询结果写入新表
create table quary_res (
id bigint not null auto_increment,
class_id bigint not null,
average double not null,
primary key(id)
);
insert into quary_res (class_id, average) select class_id, avg(score) from students group by class_id;
select class_id ‘班级‘, average ‘平均成绩‘ from quary_res;
-- 测试回滚
select * from students where id=1;
begin;
update students set name = ‘小唐改名字3‘ where id=1;
select * from students where id=1;
rollback;
select * from students where id=1;
本类排行
今日推荐
-
辽宁移动动监正式版
版本:v1.3.4
大小:34.8M
日期:2024-05-18
-
可蚁点司机官方版
版本:v1.0.0
大小:36.3M
日期:2024-05-18
-
忻州市政府网正式版
版本:v2.00
大小:13.5M
日期:2024-05-18
-
今天医生安卓版
版本:v1.0.6
大小:10.5M
日期:2024-05-18
-
伽遇瑜伽官方版
版本:v1.0.30
大小:64.5M
日期:2024-05-18
-
恒星影视仓在线观看版
版本:v1.0.1
大小:27.41MB
日期:2024-05-18
热门手游
-
像素火影破解版
版本:v1.00.42
大小:222.66MB
日期:2024-05-18
-
谁先阵亡2完整版
版本:v1.0
大小:75.17MB
日期:2024-05-18
-
闪客连打明日英雄正式版
版本:v1.0
大小:65.31MB
日期:2024-05-18
-
七日重生正式版
版本:v2.6.2
大小:532.92MB
日期:2024-05-18
-
异形探索正式版
版本:v6.6.34
大小:160.63MB
日期:2024-05-18
-
3D超级保龄球大师官方版
版本:v1.1
大小:73.15MB
日期:2024-05-18
|