MySQL4-增删改查进阶

1. 主键冲突

新增数据时,如果主键对应的数据已经存在,则会报错:

ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'

ON DUPLICATE KEY UPDATE 语法

通过 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 语法

通过 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 语法在主键冲突时,会删除冲突行,然后插入新数据

2. 蠕虫复制

从已有的表中获取数据并插入指定表中。

2.1 复制表结构

CREATE TABLE 新表名 LIKE 旧表名;

此时只有结构,没有数据。

2.2 蠕虫复制

INSERT INTO 表名[(字段列表)] SELECT 字段列表/* FROM 表名;

蠕虫复制的意义:

  • 从已有表拷贝数据到新表中。
  • 让表中数据成倍增长迅速膨胀,测试表的效率及压力(需要排除主键及唯一键)。

示例:

CREATE TABLE test2 LIKE test;
INSERT INTO test2 SELECT * FROM test;

3. 查询

查询语句完整格式:

SELECT [SELECT选型] 字段列表[字段别名]/* FROM 数据源 [WHERE子句] [GROUP BY子句] [HAVING子句] [ORDER BY子句] [LIMIT子句]

3.1 SELECT 选型

默认不写时,是 ALL

DISTINCT 去重

一个列可能会包含重复值,有时仅希望列出不同(distinct)的值。(所有字段都相同时,才被认为是重复数据)

SELECT DISTINCT * FROM 表名;          -- 全部字段查询并去重
SELECT DISTINCT column_name FROM 表名;    -- 查询一个字段并去重
SELECT DISTINCT column_name,column_name ... FROM 表名 GROUP BY 字段名1;  -- 查询多个字段并去重,此时需要用GROUP BY分组才能是字段名1不重复。

3.2 字段别名

多表联合查询时,可能会有字段同名,此时可以用字段别名解决。

字段名 [AS] 别名

示例:

mysql> SELECT id AS not_id FROM test;
+--------+
| not_id |
+--------+
|      1 |
+--------+
1 row in set (0.00 sec)

3.3 数据源

单表数据源

SELECT * FROM table;

多表数据源(没啥用)

表名用逗号分隔,最终得到的记录数是每个表的记录数的乘积(笛卡尔积)。
SELECT * FROM table1,table2,…..

子查询(数据来源是一条查询语句)

SELECT * FROM(SELECT 语句) AS 别名;

3.4 WHERE 条件子句

WHERE 子句返回 0(false)或 1(true),用来筛选数据。因为 MySQL 没有布尔类型,用 0 代表 false(枚举类型从 1 开始,字符串也是从 1 开始计算)。

判断条件:

  • 比较运算符:>,<,>=,<=,!=,<>,=,LIKE(模糊匹配),BETWEEN AND(闭区间,左值必须小于等于右值),IN/NOT IN(多数据)
  • 逻辑运算符:&& 或 AND,|| 或 OR,! 或 NOT
  • 正则表达式:REGEXP
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 是唯一一个在从磁盘获取数据的时候就开始判断的条件。从磁盘取出的每一条记录,先判断是否满足 WHERE 条件,满足则保存到内存,否则舍弃。

3.5 GROUP BY 子句

分组是为了按组统计数据。分组后,默认对得到的组进行升序排序。分成几组就会展示几条记录(每组只展示第一条记录)。

统计函数

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 分组。

group_concat() 函数

对分组结果中的某个字段进行字符串连接。

SELECT class,sex,count(*),group_concat(name) FROM myTable GROUP BY class,sex;

回溯统计 WITH ROLLUP,多字段分组回溯统计

分组后,将当前分组信息向上级分组进行汇报统计。
SELECT class,sex,count(*),group_concat(name) FROM myTable GROUP BY class,sex WITH ROLLUP;

3.6 HAVING 条件子句

类似 WHERE 子句,用于条件判断。

WHERE 子句与 HAVING 子句区别:

  • 分组统计的结果只有 HAVING 能用。WHERE 只能处理硬盘上的数据,但数据读到内存后进行分组统计,此时仍存在于内存上,只有 HAVING 能处理。
SELECT class,sex,count(*),group_concat(name) FROM myTable GROUP BY class,sex HAVING count(*) > 2;
  • HAVING 可以使用字段别名,但 WHERE 不能用。别名是在数据读入内存后才有的。
SELECT class,sex,count(*) as total,group_concat(name) FROM myTable GROUP BY class,sex HAVING total > 2;

3.7 ORDER BY 子句

排序,依赖校对集。

ORDER BY 字段名 [ASC | DESC]

其中 ASC 是升序,DESC 是降序。

单字段排序

SELECT * FROM myTable ORDER BY id;

多字段排序

先用第一个字段排序,然后对分组后的每一段数据再做排序。

SELECT * FROM myTable ORDER BY sex,name;

3.8 LIMIT 子句

限制结果,限制数量

限制长度

LIMIT 数据量

SELECT * FROM myTable LIMIT 2; -- 只查询2条记录

限制起始位置,限制数量(分页)

LIMIT 起始位置,长度
其中,起始位置OFFSET=(页码-1)*每页显示条数
长度=每页显示条数

SELECT * FROM myTable LIMIT 4,2;-- 从第4条记录开始,查询2条记录

你可能感兴趣的:(数据库,mysql,数据)