新增数据时,如果主键对应的数据已经存在,则会报错:
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
通过 ON DUPLICATE KEY UPDATE
语法,可以在 INSERT 失败时自动转为执行 UPDATE 操作:
INSERT INTO 表名[(字段列表,包括主键)] VALUES(值列表) ON DUPLICATE KEY UPDATE 字段=值[,字段=值...];
例如,如果记录存在,则修改这行记录中的某个字段:
INSERT INTO t1 (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
通过 REPLACE INTO
语法处理主键冲突时,有 3 中用法:
REPLACE INTO 表名[(字段列表,包括主键)] VALUES(值列表); -- 类似 INSERT INTO
REPLACE INTO 表名[(字段列表,包括主键)] SELECT 字段列表 FROM 另一张表; -- 从另一张表复制数据
REPLACE INTO 表名 SET col=value[,col=value...];
示例:
REPLACE INTO test(id, value) VALUES(1, "test");
REPLACE INTO test VALUES(1, "another test", NULL);
REPLACE INTO test SET id=1, value="test 666";
ON DUPLICATE KEY UPDATE
语法在主键冲突时,可以修改原数据行的部分字段REPLACE INTO
语法在主键冲突时,会删除冲突行,然后插入新数据从已有的表中获取数据并插入指定表中。
CREATE TABLE 新表名 LIKE 旧表名;
此时只有结构,没有数据。
INSERT INTO 表名[(字段列表)] SELECT 字段列表/* FROM 表名;
蠕虫复制的意义:
示例:
CREATE TABLE test2 LIKE test;
INSERT INTO test2 SELECT * FROM test;
查询语句完整格式:
SELECT [SELECT选型] 字段列表[字段别名]/* FROM 数据源 [WHERE子句] [GROUP BY子句] [HAVING子句] [ORDER BY子句] [LIMIT子句]
默认不写时,是 ALL
一个列可能会包含重复值,有时仅希望列出不同(distinct)的值。(所有字段都相同时,才被认为是重复数据)
SELECT DISTINCT * FROM 表名; -- 全部字段查询并去重
SELECT DISTINCT column_name FROM 表名; -- 查询一个字段并去重
SELECT DISTINCT column_name,column_name ... FROM 表名 GROUP BY 字段名1; -- 查询多个字段并去重,此时需要用GROUP BY分组才能是字段名1不重复。
多表联合查询时,可能会有字段同名,此时可以用字段别名解决。
字段名 [AS] 别名
示例:
mysql> SELECT id AS not_id FROM test;
+--------+
| not_id |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
SELECT * FROM table;
表名用逗号分隔,最终得到的记录数是每个表的记录数的乘积(笛卡尔积)。
SELECT * FROM table1,table2,…..
SELECT * FROM(SELECT 语句) AS 别名;
WHERE 子句返回 0(false)或 1(true),用来筛选数据。因为 MySQL 没有布尔类型,用 0 代表 false(枚举类型从 1 开始,字符串也是从 1 开始计算)。
SELECT * FROM people WHERE last_name="Allen"; -- 完全匹配
SELECT * FROM people WHERE last_name LIKE "A%"; -- 以 A 开头
SELECT * FROM people WHERE last_name REGEXP "^A"; -- 以 A 开头
SELECT * FROM people WHERE last_name REGEXP "^A" && gender="f"; -- 需同时满足所有条件
SELECT * FROM people WHERE last_name REGEXP "^A" AND gender="f";
SELECT * FROM people WHERE age BETWEEN 20 AND 30; -- age在[20,30]之间
SELECT * FROM people WHERE ID IN (1,3); - ID 是 1 或 3
WHERE 是唯一一个在从磁盘获取数据的时候就开始判断的条件。从磁盘取出的每一条记录,先判断是否满足 WHERE 条件,满足则保存到内存,否则舍弃。
分组是为了按组统计数据。分组后,默认对得到的组进行升序排序。分成几组就会展示几条记录(每组只展示第一条记录)。
count():统计分组后每一组有多少条记录。参数可以是*(统计记录数)或字段(当字段为NULL时忽略)。
max():求分组中的最大值。
min():求分组中的最小值。
avg():求平均值。
sum():求和。
mysql> SELECT last_name,count(*),max(dob) FROM people;
+-----------+----------+------------+
| last_name | count(*) | max(dob) |
+-----------+----------+------------+
| Akroyd | 9 | 1990-03-01 |
+-----------+----------+------------+
1 row in set (0.00 sec)
mysql> SELECT last_name,count(*),max(dob) FROM people GROUP BY gender;
+-----------+----------+------------+
| last_name | count(*) | max(dob) |
+-----------+----------+------------+
| Bssia | 1 | 1990-03-01 |
| Allen | 8 | 1990-03-01 |
+-----------+----------+------------+
2 rows in set (0.00 sec)
示例:
SELECT class,sex,count(*) FROM myTable GROUP BY class,sex;
最终得到的数据是将表中所有的数据,先用 class 分组,然后在每一个分组中用 sex 分组。
对分组结果中的某个字段进行字符串连接。
SELECT class,sex,count(*),group_concat(name) FROM myTable GROUP BY class,sex;
分组后,将当前分组信息向上级分组进行汇报统计。
SELECT class,sex,count(*),group_concat(name) FROM myTable GROUP BY class,sex WITH ROLLUP;
类似 WHERE 子句,用于条件判断。
SELECT class,sex,count(*),group_concat(name) FROM myTable GROUP BY class,sex HAVING count(*) > 2;
SELECT class,sex,count(*) as total,group_concat(name) FROM myTable GROUP BY class,sex HAVING total > 2;
排序,依赖校对集。
ORDER BY 字段名 [ASC | DESC]
其中 ASC 是升序,DESC 是降序。
SELECT * FROM myTable ORDER BY id;
先用第一个字段排序,然后对分组后的每一段数据再做排序。
SELECT * FROM myTable ORDER BY sex,name;
限制结果,限制数量
LIMIT 数据量
SELECT * FROM myTable LIMIT 2; -- 只查询2条记录
LIMIT 起始位置,长度
其中,起始位置OFFSET=(页码-1)*每页显示条数
长度=每页显示条数
SELECT * FROM myTable LIMIT 4,2;-- 从第4条记录开始,查询2条记录