目录
关于对字段的分割find_in_set('参数',字段名);
left函数及扩展right函数和SUBSTRING、SUBSTRING_index
我这篇为mysql的一些命令的杂记
注:本博客的sql我都有本地执行,但可能会因为博客的空格/换行符导致sql报错,如果有报错可以手打一遍或者在编辑器上重新复制下,我有遇到过sql 粘贴上来 再copy实用报错
mysql的系统方面
1> mysql的登录命令:
下面是几种登陆到MySql数据库的登陆方式代码(我最喜欢2),刚刚安装mysql的root账户是没有密码的.
1.mysql -u root -ppassword
2.mysql -u root -p
Enter password:password
3.mysql -h localhost -u root -ppassword
4.mysql -h 127.0.0.1 -u root -ppassword
2>创建,删除,使用数据库:
create database '数据库名';
use '数据库名';
drop database '数据库名';
mysql函数
关于对字段的分割find_in_set('参数',字段名);
今天有一个业务场景需要一个字段进行一个查询,而改字段存放的是标签, 格式为:101,102,103
所以在查询的时候需要将该字段进行切割,当然也可以在查询的时候在该字段的内容前后分别加上,号来进行like 查询.
不过呢我想用切割的来,mysql作为一个成熟的数据库果然还是有支持的机制的,字段值用英文逗号分隔,
比如‘未分组,VIP会员,广东客'查询时
select * from `table_a` where id=20 and find_in_set('未分组', group_name);
或者
select * from `table_a` where id=20 and find_in_set('未分组', group_name)>0;
这两种都可以 但是在hibernate框架中只能用第二种,不然会抛异常
因为是原生支持的做法,mysql会对其进行优化.
最近在做一个根据省份的首字母进行排序的需求, 其中有许多接触的点感觉可以记一下.
在网上找资料的结果
select *
FROM 表名
order by ELT(
INTERVAL(
CONV(
HEX(left(CONVERT(字段名 USING gbk),1)),
16,10),
0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,0xC8F6,
0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),
'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z') asc
如上,一共用来6个函数:
one by one
convert函数及扩展cast函数
convert函数有两种 :
- convert(参数,类型) 功能等同于 cast(参数 as 类型) 将参数转换为指定类型
- convert(参数 using 字符集) 将参数转换为指定字符集
- cast(参数 AS 类型) convert(参数,类型)
可以转换的类型是有限制的。这个类型可以是以下值其中的一个:
二进制,同带binary前缀的效果 : BINARY
字符型,可带参数 : CHAR()
日期 : DATE
时间: TIME
日期时间型 : DATETIME
浮点数 : DECIMAL
整数 : SIGNED
无符号整数 : UNSIGNED
例:
select convert('123.26' ,DECIMAL(20,2)); -- 结果:123.26
select cast('123.26' AS DECIMAL(20,1) ); -- 结果:123.3
有细心的小伙伴应该能发现两个结果不一样, 因为我把例2 的decimal的精度改为1 , 所以cast会先进行一个四舍五入然后再进行转换操作.
convert和cast 一样也会四舍五入 就不在花篇幅了.
convert(参数 using 字符集)
例:
select convert('gbk' using utf8); -- 结果:gbk
没有效果是因为函数的作用只是修改字符集,但是内容是不变的 所以看起来没感觉
left函数及扩展right函数和SUBSTRING、SUBSTRING_index
- left(字符串,截取多少个) :从左侧截取
- right(字符串,截取多少个) 从右侧截取
- SUBSTRING(字符串,从哪个位置截取,截取多少个)
- substring_index(被截取字符串,关键字,关键字出现的次数) 关键字:检索匹配的条件 关键字出现的次数 n: 正数截取到第n个关键字 负数:从倒数第n个关键字开始截取 如果关键字在被截取的字符串中不存在则完整返回截取的字符串
例:后边的注释为结果
select left('12345678',2); -- 结果:12
select right('12345678',2); -- 结果:78
select SUBSTRING('12345678',2,3); -- 结果:234
select substring_index('12324256278',22,-1); -- 结果:12324256278
select substring_index('12324256278',2,-1); -- 结果:78
select substring_index('12324256278',2,3); -- 结果:12324
HEX函数
hex(参数)将参数转换为16进制 如果参数是数字且不是整数会先进行四舍五入然后转16进制
例:这里的‘abc’ 应该是我本地的编码对应的值 , 如果本地不是编码abc对应的支不是97、98、99 则得到结果应该就不是616263了.
这个结论是不是正确我没有求证,如果哪位知道 还望指点, 但我本地的结果是这样的
SELECT HEX('abc'); ---》 先得到a,b,c的ascii码97, 98, 99再将其转为16进制 , 得到结果:616263
CONV函数
CONV(参数,原进制,目标进制); 将指定进制的参数转换为另一种进制
例:
select conv('a' , 16,10); -- 结果:10
select conv('2' , 10,2); -- 结果:10 这是二进制的1 0
select conv('11000' , 2,16);-- 结果:18
INTERVAL函数
INTERVAL(n, n1,n2,n3,n4,n5); 返回最小大于n 的值的索引 n1 -》0 n2-》1
例:
select INTERVAL(2,4,6,8,10,34,56); -- 结果: 0
select INTERVAL(6,4,6,8,10,34,56); -- 结果: 2
select INTERVAL(66,4,6,8,10,34,56); -- 结果: 6
elt函数
elt(n,'字符串1','字符串2','字符串3','字符串4','字符串5','字符串6','字符串7'); 返回指定索引的值 索引从1 开始 索引越界的返回null
例:
select elt(1,'字符串1','字符串2','字符串3','字符串4','字符串5','字符串6','字符串7'); 字符串1
select elt(0,'字符串1','字符串2','字符串3','字符串4','字符串5','字符串6','字符串7'); null
select elt(10,'字符串1','字符串2','字符串3','字符串4','字符串5','字符串6','字符串7'); null
至此上边的所有的函数都以清楚,回过头看sql
select *
FROM 表名
order by ELT(
INTERVAL(
CONV(
HEX(left(CONVERT(字段名 USING gbk),1)),
16,10),
0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,0xC8F6,
0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),
'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z') asc
过程是
得到字段首先将字符集转为gbk获得最左侧的字符,得到16进制的值 ,将16进制转换为10进制 然后通过interval获得对应的索引值. 最后通过elt函数得到对应的首字母;
其中两处标红的地方:
- 转为gbk的原因是gbk是根据康熙字典来的 所以本身就是根据拼音排好的序
- 将16进制转换为10进制 这一步也许会有同学疑惑 通过hex函数转换后的结果不是已经是16进制了吗?直接进行16interval的函数转换不行吗?
这里我们通过一个例子就能明白
例:
select HEX('c') - 17; -- 结果:46
还记得之前hex的例子吗?
SELECT HEX('abc'); -- 结果:616263
16进制的 63-17 应该等于52才对 可是结果确是46 很明显mysql的hex函数只是将进制转换
但是interval函数处理参数的时候可不会看你是不是hex函数返回的16进制 他只看数值所以他就认为是十进制跟后边比较得出的结果必然是错误的.
那我们希望是正确的值进行计算怎么办?所以conv函数上场
例:
select conv(HEX('c'),16,10) - 17; -- 结果:82
'c'的16进制我们之前已经得到了63, 而'c'对应的accII码为97 , 97-17 = 82 正确
到此 这个根据省份排序的sql查询逻辑已经明了.
但是我发现一个问题,就是多音字!!! 但是好消息是我国的省份只有直辖市 重庆是多音字
例:
select
elt(INTERVAL(CONV(HEX(left(CONVERT('重庆' USING gbk),1)),16,10),
0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,0xC8F6,
0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z')
结果:上图更有说服力 哈哈
结果得到首字母为Z 估计是任务它读zhong吧
不幸中之大幸是只有一个,所以我是这么做的 判断下如果是重字替换成没有多音的字且和重(chong)首字母相同就行了
select
elt(INTERVAL(CONV(HEX(case left(CONVERT('重庆' USING gbk),1) when '重' then '葱' else left(CONVERT('重庆' USING gbk),1) end ),16,10),
0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,0xC8F6,
0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z')
结果:
最终的sql为:
select *
FROM 表名
order by ELT(
INTERVAL(
CONV(
HEX(case left(CONVERT(字段名 USING gbk),1) when '重' then '葱' else left(CONVERT(字段名 USING gbk),1) end ),
16,10),
0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,0xC8F6,
0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),
'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z') asc