SQL基础-DML
insert语句
mysql> insert into students(sid,sname,scardid,saddr,hobby,salary,sdate) values(1000,'lisi','110102','北京市','足 球,羽毛球',10001.00,now()); mysql> create table t1(id int,name varchar(10)); Query OK, 0 rows affected (0.02 sec) mysql> alter table t1 add primary key (id); Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> insert into t1 values(1,'tom'); Query OK, 1 row affected (0.01 sec)
使语句可重复执行 insert ignore
mysql> insert into t1 values(1,'jerry'); ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> insert ignore into t1 values(1,'jerry'); Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> show warnings; +---------+------+---------------------------------------+ | Level | Code | Message | +---------+------+---------------------------------------+ | Warning | 1062 | Duplicate entry '1' for key 'PRIMARY' | +---------+------+---------------------------------------+ 1 row in set (0.00 sec)
插入多条数据语句
mysql> insert ignore into t1 values(2,'jerry'),(3,'jack'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0
其他插入语句实例
mysql> insert into t1 set id=4,name='lucy'; Query OK, 1 row affected (0.00 sec) mysql> insert into t1 select * from t2;
使用replace替换数据
## 注意,在没有约束的时候,会新插入数据
mysql> replace into t1 values(4,'lily'); Query OK, 2 rows affected (0.00 sec) mysql> select * from t1; +----+-------+ | id | name | +----+-------+ | 1 | tom | | 2 | jerry | | 3 | jack | | 4 | lily | +----+-------+ 4 rows in set (0.00 sec) mysql> create table t2 as select * from t1; Query OK, 4 rows affected (0.03 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> desc t2; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | | name | varchar(10) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> select * from t2; +----+-------+ | id | name | +----+-------+ | 1 | tom | | 2 | jerry | | 3 | jack | | 4 | lily | +----+-------+ 4 rows in set (0.01 sec) mysql> replace into t2 values(4,'lucy'); Query OK, 1 row affected (0.01 sec) mysql> select * from t2; +----+-------+ | id | name | +----+-------+ | 1 | tom | | 2 | jerry | | 3 | jack | | 4 | lily | | 4 | lucy | +----+-------+ 5 rows in set (0.00 sec) mysql> alter table t1 add unique key unq_name(name); Query OK, 0 rows affected (0.16 sec) Records: 0 Duplicates: 0 Warnings: 0
update
update TABLE_NAME SET xxx=xxx where
注意点: 更新列的个数,where条件最好带索引列,更新索引列的值时,有可能会出现页分片,尽量在业务不繁忙的时候更新索引列。
当有索引的时候update是顺序修改,在做批量修改的时候可以使用order by
mysql> select * from t1; +----+-------+ | id | name | +----+-------+ | 3 | jack | | 2 | jerry | | 4 | lily | | 1 | tom | +----+-------+ 4 rows in set (0.00 sec) mysql> update t1 set id=id+1; ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY' mysql> update t1 set id=id+1 order by id desc; Query OK, 4 rows affected (0.00 sec) Rows matched: 4 Changed: 4 Warnings: 0 mysql> select * from t1; +----+-------+ | id | name | +----+-------+ | 4 | jack | | 3 | jerry | | 5 | lily | | 2 | tom | +----+-------+ 4 rows in set (0.00 sec)
limit 限制改多少行
mysql> alter table t1 add age int unsigned; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> update t1 set age=20 where id>2 limit 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from t1; +----+-------+------+ | id | name | age | +----+-------+------+ | 2 | tom | NULL | | 3 | jerry | 20 | | 4 | jack | 10 | | 5 | lily | 10 | +----+-------+------+ 4 rows in set (0.00 sec)
delete
delete from t2 where id=4; 注意点: where 条件,索引
伪删除(在表中添加状态列state,update时加条件)
mysql> alter table t2 add column state int not null default 1; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc t2; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | | name | varchar(10) | YES | | NULL | | | state | int(11) | NO | | 1 | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> select * from t2; +----+-------+-------+ | id | name | state | +----+-------+-------+ | 1 | tom | 1 | | 2 | jerry | 1 | | 3 | jack | 1 | | 4 | lily | 1 | | 4 | lucy | 1 | +----+-------+-------+ 5 rows in set (0.00 sec) mysql> update t2 set state=0 where id >=4; Query OK, 2 rows affected (0.01 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> select * from t2 where state =1; +----+-------+-------+ | id | name | state | +----+-------+-------+ | 1 | tom | 1 | | 2 | jerry | 1 | | 3 | jack | 1 | +----+-------+-------+ 3 rows in set (0.00 sec)
select
select 查询参数(变量)值
mysql> select @@innodb_flush_log_at_trx_commit; +----------------------------------+ | @@innodb_flush_log_at_trx_commit | +----------------------------------+ | 1 | +----------------------------------+ 1 row in set (0.00 sec) mysql> select @@datadir; +------------------------+ | @@datadir | +------------------------+ | /data/mysql/data_3306/ | +------------------------+ 1 row in set (0.00 sec) mysql> show variables like '%trx%'\G *************************** 1. row *************************** Variable_name: innodb_api_trx_level Value: 0 *************************** 2. row *************************** Variable_name: innodb_flush_log_at_trx_commit Value: 1 2 rows in set (0.00 sec)
select查询函数
mysql> select pi()*2*5 from dual; +-----------+ | pi()*2*5 | +-----------+ | 31.415927 | +-----------+ 1 row in set (0.00 sec) mysql> select current_user(); +----------------+ | current_user() | +----------------+ | root@localhost | +----------------+ 1 row in set (0.00 sec)
select标准使用
单表查询
1、 多子句的执行顺序
select from 从哪来 where 过滤条件 group by 分组条件 select_list 列条件 having 后过滤条件 order by 排序条件 limit 分页
from子句应用
1. 获取世界上所有城市信息 SELECT * FROM city; ===> SELECT id,NAME,coutrycode,District ,population FROM city;
select应用举例
1、获取世界上所有城市名和人口数
SELECT NAME,population FROM city;
2、where 子句应用
2.1 等值查询
2.1.1 查询中国(CHN)所有的城市
SELECT * FROM city WHERE countrycode='CHN';
2.1.2 查询中国或美国的所有城市信息
SELECT * FROM city WHERE countrycode='CHN' OR countrycode='USA' ; SELECT * FROM city WHERE countrycode IN ('CHN','USA'); SELECT * FROM city WHERE countrycode='CHN' UNION ALL SELECT * FROM city WHERE countrycode='USA' ; SELECT countrycode,CASE countrycode WHEN countrycode = 'CHN' THEN NAME END FROM city;
2.1.3 UNION和UNION ALL 差别,union 是要去重复的。
说明: union all 语句在索引合理的时候,比in性能好一些
如果说,在索引不合理的时候,需要多次查同一表时,性能肯能不如in
例如:以下语句,最好改写为case语句
SELECT SUM(invalid_count) as invalid_count, SUM(confirm_count) as confirm_count,SUM(not_confirm_count) as not_confirm_count,SUM(total_count) as total_count FROM ( select count(att.LogID) as invalid_count, 0 as confirm_count,0 as not_confirm_count,0 as total_count,bp.city_id FROM builder_project_info as bp JOIN attendentlog as att ON bp.project_id = att.CompanyID WHERE att.CompanyID in (SELECT project_id from builder_project_info WHERE city_id = 407) and att.LogTime like "2019-06%" and att.state = 2 GROUP BY bp.city_id UNION all ( select 0 as invalid_count, count(att.LogID) as confirm_count,0 as not_confirm_count,0 as total_count,bp.city_id FROM builder_project_info as bp JOIN attendentlog as att ON bp.project_id = att.CompanyID WHERE att.CompanyID in (SELECT project_id from builder_project_info WHERE city_id = 407) and att.LogTime like "2019-06%" and att.state = 1 GROUP BY bp.city_id ) UNION all ( select 0 as invalid_count, 0 as confirm_count,count(att.LogID) as not_confirm_count,0 as total_count,bp.city_id FROM builder_project_info as bp JOIN attendentlog as att ON bp.project_id = att.CompanyID WHERE att.CompanyID in (SELECT project_id from builder_project_info WHERE city_id = 407) and att.LogTime like "2019-06%" and att.state = 0 GROUP BY bp.city_id ) UNION all ( select 0 as invalid_count, 0 as confirm_count,0 as not_confirm_count,count(att.LogID) as total_count,bp.city_id FROM builder_project_info as bp JOIN attendentlog as att ON bp.project_id = att.CompanyID WHERE att.CompanyID in (SELECT project_id from builder_project_info WHERE city_id = 407) and att.LogTime like "2019-06%" GROUP BY bp.city_id ) ) as a GROUP BY a.city_id
改写后:
SELECT COUNT(CASE WHEN att.state=0 THEN 1 END) AS a, COUNT(CASE WHEN att.state=1 THEN 1 END) AS b, COUNT(CASE WHEN att.state=2 THEN 1 END) AS c, sum(att.LogID) FROM builder_project_info AS bp JOIN attendentlog AS att ON bp.project_id = att.CompanyID WHERE bp.city_id=407 AND att.LogTime LIKE "2019-06%" AND att.state IN (0,1,2) GROUP BY bp.city_id;
2.1.3 WHERE + LIKE 使用(字符串列)
--- 查询一下国家的code是CH开头的。
SELECT * FROM city WHERE countrycode LIKE 'CH%';
注意不要出现 LIKE '%CH%',不走索引。
4. where 不等值查询 (> < >= <=,!= <>,not in)
不等于!=、<>、not in查询不走索引,除非是主键列
例如:
mysql> desc select CountryCode,name from city where id>100;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | city | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 2094 | 100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
SELECT * FROM city WHERE population<100;
SELECT * FROM city WHERE countrycode != 'CHN' ;
SELECT * FROM city WHERE countrycode NOT IN
('CHN','USA');
SELECT * FROM city WHERE Population>=1000000 AND
Population<=2000000;
SELECT * FROM city WHERE Population BETWEEN 1000000 AND
2000000;
-- group by + 聚合函数
(sum(),avg(),count(),max(),min(),group_concat())
-- 1. 统计city表中,每个国家的城市个数
SELECT countrycode,COUNT(id) FROM city GROUP BY countrycode;
-- 2. 统计一下每个国家的总人口
SELECT countrycode ,SUM(population)
FROM city
GROUP BY countrycode;
-- 3. 统计一下中国每个省的总人口
SELECT district ,SUM(population)
FROM city
WHERE countrycode='CHN'
GROUP BY district;
-- 4. 统计每个国家的城市个数和城市名
SELECT countrycode,COUNT(id),GROUP_CONCAT(NAME) FROM
city
GROUP BY countrycode;
执行逻辑:
1. 按照group by条件进行排序
2. 去重复
3. 聚合列
sql_mode问题:
mysql> SELECT countrycode,id FROM city
-> GROUP BY countrycode;
ERROR 1055 (42000): Expression #2 of SELECT list is not
in GROUP BY clause and contains nonaggregated column
'world.city.ID' which is not functionally dependent on
columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by
-- 5.分组聚合group_concat(column_name):将返回的column值按一行显示,避免1对多
-- having 后判断(不走索引)
-- 1. 统计一下中国每个省的总人口,将总人口超过500w的显示出来
SELECT district ,SUM(population)
FROM city
WHERE countrycode='CHN'
GROUP BY district
HAVING SUM(population) >5000000;
--- order by 子句应用(不走索引)
-- 统计一下中国每个省的总人口,将总人口超过500w的显示出来,总人口
从大到小排序
SELECT district ,SUM(population)
FROM city
WHERE countrycode='CHN'
GROUP BY district
HAVING SUM(population) >5000000
ORDER BY SUM(population) DESC ;
-- 查询中国所有城市人口数,按从大到小排序
SELECT NAME ,population FROM city
WHERE countrycode='CHN'
ORDER BY population DESC;
8.0 新姿势: 倒序索引
select * from t1 order by a asc , b desc;
idx_a_b(a,b) ===== > idx(a asc,b desc)
--- limit 子句使用
SELECT district ,SUM(population)
FROM city
WHERE countrycode='CHN'
GROUP BY district
HAVING SUM(population) >5000000
ORDER BY SUM(population) DESC
LIMIT 5 OFFSET 1;
SELECT district ,SUM(population)
FROM city
WHERE countrycode='CHN'
GROUP BY district
HAVING SUM(population) >5000000
ORDER BY SUM(population) DESC
LIMIT 1,5;
count(*)和count(1)的区别:
count(*)用到局和索引 count(1)全表扫描
多表查询
departments # 部门表
dept_no(部门编号),
dept_name(部门名称)
dept_emp #部门-员工关系表
emp_no(员工编号),
dept_no(部门编号),
from_date,to_date
dept_manager #部门-经理关系表
from_date(任职起始)
to_date(任职结束),
dept_no(部门编号),
emp_no(员工编号)
employees #员工表
emp_no(员工编号),
birth_date(生日),
first_name(名),
last_name(姓),
gender(性别),
hire_date(离职日期)
salaries #薪水表
emp_no(员工编号),
salary(年薪),
from_date(起始日期),
to_date(结束日期)
titles #职称表
emp_no(员工编号),
title(职称),
from_date(起始时间),
to_date(结束时间)
-- 说明: 别名应用
表别名: 在任意子句中调用表名时,都可以使用别名替代
列别名: 在having和order by子句中可以调用
-- 多表连接工作逻辑
1. 优化器,在内连接中,选择驱动表
(1) 多张表时,从左到右,查看表中索引情况,有索引选为驱动表
(2) 如果第一张没有,直到找到第一只张表有索引的表作为驱动表
(3) 如果都没有,则选择行数少的表
2. 多表连接算法
SNLJ
BNLJ
BKAJ
3. 优化重点
强制“小表”为驱动表(left join会强制使用左表为驱动表,right join 同理)
建立合适的索引
开启优化算法
set global
optimizer_switch='batched_key_access=ON,mrr_cost_based=
off';
4. letf join 优化not in 语句
posted on 2021-04-22 17:40 hopeless-dream 阅读(69) 评论(0) 编辑 收藏 举报