在进行复杂业务逻辑sql编写时,往往理不清多张表之间的连接关系,这时你需要一个清晰的思路来串连多张表。第一个误区就是根据查询条件认为查询字段所在表为主表,这是错误的,表的连接顺序往往是固定的,查询条件字段所在表是主表是个伪命题。
1、根据某个字段分组,但是字段值为某些值得是有归为一组
比如记录如下:
id status
100 1
101 2
102 3
103 4
104 5
105 99
106 98
将status 5 99 98的归为一个组,其他的按status值分组
SELECT
count(*) as count,
case when status in (90,98,5) then 5 else status end as optyStatus
from some_test
where `status` is not null
group by case when status in (90,98,5) then 5 else status end
2、2个表间复制数据
INSERT INTO hb_t_nickname1(nickname,gender,is_deleted)
SELECT DISTINCT nickname,gender,is_deleted FROM hb_t_nickname;
3、删除重复数据
注意:不能重命名
DELETE hb_t_iu from hb_t_iu,(
SELECT
max(id) id,
tel
FROM
hb_t_iu
GROUP BY
tel
HAVING
count( * ) > 1 ) iu2
where hb_t_iu.tel = iu2.tel
and hb_t_iu.id < iu2.id
4、连表更新
UPDATE huc_user huser
inner join hb_t_iu iu on huser.mobile_no = iu.tel
SET huser.gender = iu.gender
5、取余数
mod(m,n)
m是被取余的数,n是模
6、计算datetime类型日期和当前时间天数
TIMESTAMPDIFF(YEAR, huser.birth_time, now())
需要注意的是,两个日期之间的位置和计算规则,第一个时间是beginTime,后一个是endTime,beginTime数值上要比endTime小,否则会出现负数,第一个参数是Unit,取值可以有:
MICROSECOND 微秒
SECOND 秒
MINUTE 分钟
HOUR 小时
DAY 天
WEEK 星期
MONTH 月
QUARTER 季度
YEAR 年
7、Navicate导出数据时某个字段被处理成无规则串?
查看这个字段类型,longtext有这种情况,使用cast(field as char)转换一下即可。
8、mysql between and使用
between and 的左右边界是闭合的,但是在处理时间时需要注意,如果是datetime类型,且入参没有时间时,时间默认为00:00:00,如:
select * from t_x where created_time between '2020-01-01' and '2020-01-01';
这样两个时间都会是2020-01-01 00:00:00,这样很可能跟你的预期不符合。
9 trur flase含义
mysql中boolean用tinyint(1)实现,true=1,false=2
select true + 1 // 2
10 mysql varchar 和int比较
2ABC3 =2 // true
2abc > 1 // true
mysql会把字符串类型转换成数字,从第一个字符开始解析,到第一个字符不符合结束
11 count()和sum()
count(expression) 函数,注意入参是表达式
sum(expression) 函数,入参也是表达式
count(*)=count(1) // 统计行数,不管字段是否为空
count(field) // 字段为null的会被排除,空串和空白字符依然被计算
sum(field) // 数值类型没什么,如果field是varchar,如果存了实数也没什么,如果存了非实数字符串,会被解析成0
sum(2) // 是每一列都是2来相加
sum(field=2) // 表达式成立就是true也即1
count(var=2) // 表达式没有意义了,true或false结果都一样
12 汇总
select ifnull(a,汇总),count(*) group by a with rollup // 就是汇总
13 一对多连接去重
怎么处理?
14 查询表的所有字段
show full columns from t;
15 查询一张表所有字段饱和度?
16 group by 没有的字段需要返回?
当查询简单时,可以通过构建临时表完成如:select x union select y union select z构建一个临时结果作为主表,但是关联的表过多时,比如需要通过能关联上另一张表作为选中的结果并计算合计,这样就很难操作了,只能在Java中操作,如何操作,定义一个final List,然后遍历,将查询结果集转换成map,然后构建一个新List返回,这样即可以填充没有的字段,还能保证顺序,其中List转Map需要我们掌握。
17 编码选择
2、关于字段编码选择,有个同事建立的某张表使用了不同的字符编码,导致大小写敏感了,相关字段索引也无法使用。mysql字符集默认的编码查询:show charset;
如果指定了表的字符集,那么字段的字符编码就是默认的了,其中utf8mb4_bin大小写敏感,使用时注意。
18 date_format()的迷惑点
select DATE_FORMAT('2020-09','%Y-%m') // 输出null
这种用法有可能出现在前端传参和已有字段比较的情况,为什么输出null,因为date_format接受的第一个参数类型是date,至少要有年月日,这里只有年月,不被认为是日期,所以格式化无效,直接输出null,使用的时候需要警惕。
19 MySQL数据库约束
约束(constraint),使用来保证数据库中数据完整性(实体完整性(Entity Integrity)、域完整性(Domain Integrity)、参照完整性(Referential Integrity)、用户定义的完整性(User-definedIntegrity))的手段之一。
MySQL中常用的约束:
约束类型: | 主键 | 外键 | 唯一 | 非空 | 自增 | 默认值 |
---|---|---|---|---|---|---|
关键字: | primary key | foreign key |
unique |
not null |
auto_increment |
default |
primary key = unique + not null
使用方式如下:
ALTER TABLE `zz` ADD PRIMARY KEY ( `id` ) // 添加主键,不需要给主键起名字
ALTER TABLE `zz` DROP PRIMARY KEY // 删主键,主键不需要名称,因为只有一个,此字段不能有自增属性,否则删不了。
ALTER TABLE zz ADD CONSTRAINT fk_prod_id FOREIGN KEY (product_id) REFERENCES product (id); // 添加外键
ALTER TABLE `zz` DROP FOREIGN KEY `fk_prod_id`; // 删除外键
ALTER TABLE zz ADD UNIQUE KEY uk_2(name,product_id); // 添加唯一约束
ALTER TABLE zz ADD UNIQUE uk_2 (NAME, product_id); // 添加唯一约束可以省略 KEY关键字
ALTER TABLE zz ADD CONSTRAINT UNIQUE uk_2 (NAME, product_id); // 添加唯一约束多加一个constraint关键字也行
ALTER TABLE zz DROP INDEX uk_2; // 删除唯一约束,注意这里已经变成index了
ALTER TABLE zz MODIFY product_id VARCHAR (12) NOT NULL; // 添加非空约束
ALTER TABLE zz MODIFY product_id VARCHAR (12) NULL; // 删除非空约束
MySQL表中只能设置一个自增长字段【必须是key(其他普通字段不行))】
ALTER TABLE zz MODIFY product_id INT UNSIGNED AUTO_INCREMENT; // 添加自增
ALTER TABLE zz MODIFY product_id INT UNSIGNED;// 删除自增
20 常用表结构修改
修改字段编码使支持emoji表情
ALTER TABLE t_user MODIFY `signature` VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '';
添加单个或多个字段索引
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
主键一定是索引,索引未必是主键,复合主键一定建立复合索引,复合主键不能重复,每个键都不能为空。
联合主键:指多张表的主键组合,多半出现在多对多时的中间表上
复合主键:一张表中多个字段组成primary key,一张表只能有一个主键,主键分为单一主键和复合主键
添加字段
ALTER TABLE xxx_yy ADD terminal_type tinyint (2) unsigned DEFAULT '0' COMMENT '注释';
21 case when 2种用法
-- 简单case函数
case sex
when '1' then '男'
when '2' then '女’
else '其他' end
-- case搜索函数
case when sex = '1' then '男'
when sex = '2' then '女'
else '其他' end
需要注意的是case when搜索函数和 else if功效一样,当前的满足了,就不会进行下面的判断了,使用时需要注意这一点。
22 关于连接
1 连接基础
left join = left outer join
right join = right outer join
inner join = join
full join = full outer join(left join + right join)
对于left join,条件写在on后面和where后面是有区别的,写在on后的不会影响主表记录,哪怕条件是关于主表的,写在where后面的条件是针对连接后的结果集,可以影响到主表记录。如:
SELECT
u.NAME,
ur.role_id
FROM
user_cn u
LEFT JOIN user_role ur ON u.id = ur.user_id AND u.NAME = '张飞' // 这里的u条件不会影响主表
2 多表连接
SELECT
u. NAME,
r.role_name
FROM
user_cn u
LEFT JOIN user_role ur ON u.id = ur.user_id
INNER JOIN role r ON ur.role_id = r.id
可以看到,多表连接后,如果有left join和inner join同时出现,那么inner join的排除效果就会体现到主表上了,连接顺序对结果是没有影响的,我们可以看成是inner join和前面所有连接结果再进行运算,那么自然就会排除。看这种复杂连接关系,可以先分清对应关系,这里u对ur是一对多(u和ur是多对多),ur对r是一对一。