NAVICAT快捷键:
ctrl + r:运行当前查询页面的所有sql语句 ctrl + shift + r:运行所选择的sql语句 ctrl + q:打开一个新的查询页面 ctrl + /:注释 ctrl + shift + ctrl:取消注释 ctrl + l:删除当前行 ctrl + d:复制当前行 ctrl + f:查找当前页面的内容
注意事项:
1、枚举:tinyint 类型; 2、数据库表的默认编码格式:utf8mb4; 3、单个字段不用特意写明编码格式,好像默认utf8; 4、创建时间修改时间用 now() 或者 什么当前时间
DDL修改(关键字COLUMN可要可不要,只不过有了这个更加好理解):
ALTER TABLE test ADD COLUMN dd VARCHAR(20) DEFAULT NULL COMMENT 'cao dd' AFTER `haha`; ALTER TABLE test DROP COLUMN dd; ALTER TABLE test MODIFY COLUMN cc CHAR(30) DEFAULT NULL COMMENT 'cc';
SHOW:
show create table `user`; -- 查看建表语句 SHOW VARIABLES LIKE '%datadir%'; -- 查看本地MySQL数据的保存路径,我的点人电脑放在:C:ProgramDataMySQLMySQL Server 8.0Data SHOW FULL COLUMNS FROM tableshaha; -- 超级强大,一定要记住,查看表注释的另外一种方法,比information schema强大多了 SHOW COLUMNS FROM tableshaha; -- 在我看来,和上面的区别就是,上面显示的有注释,这个没有注释,这个是简短版的 SHOW TABLE STATUS LIKE '%org%' -- 对于InnoDB类型的表,这样来显示信息,终于找到了一种方法来快速模糊查找表了 SHOW INDEX FROM emp -- 查询索引的具体信息 SHOW CREATE VIEW test_view -- 查询视图信息,目前对于我来说没有什么用 SHOW STATUS LIKE 'Com_%'; -- 查询执行增删改查的情况,目前对于我来说没有什么用 SHOW STATUS LIKE 'Handler_read%'; -- 查看索引的使用情况,目前对于我来说没有什么用 SHOW DATABASES; -- 查看当前连接下有多少数据库 USE test; -- 选择某一个数据库 SHOW tables; -- 查看表
information_schema(常用的主要还是第一条):
SELECT COLUMN_NAME,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,COLUMN_DEFAULT,COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_NAME = 'tm_esim_special_pay'; -- 这个经常用,因为可以快速查看注释嘛 SELECT TABLE_NAME,COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE DATA_TYPE = 'enum'; -- 这个在一次工作当中发挥了重要的作用,因为那个时候我要把整个数据库表里面的枚举类型变成varchar类型
其它:
INSERT INTO t2 (SELECT * FROM t1) -- 这样插入都行很厉害,相当于将数据复制多一份,t2的表结构必须与t1的一模一样,不推荐这种方式 INSERT INTO t3 (col1,col2,col3) (SELECT col4,col5,col6 FROM t4) -- 这样插入,但是后面的一定要与字段个数一致 SELECT deptno,count(*) FROM emp GROUP BY deptno WITH ROLLUP -- 既要统计各部门人数,又要统计总人数,这个函数不能与orderby同时使用 SELECT * FROM emp ORDER BY RAND() -- 将行打乱,随机行 SELECT * FROM emp PROCEDURE ANALYSE(); -- 这个sql语句分析值与字段之间的关系真的很强大 SELECT VERSION(); -- 查询数据库工具版本 -- 定期检查表,优化表 ANALYZE TABLE emp; CHECK TABLE emp; OPTIMIZE TABLE emp;
处理时间:
SELECT CURDATE(); -- 当前日期 SELECT CURTIME(); -- 当前时间 SELECT NOW(); -- 当前日期时间 SELECT SYSDATE(); -- 当前日期时间 -- NOW()与SYSDATE()的区别: -- NOW():这条sql语句执行时立刻得到当前时间值; -- SYSDATE():执行到当前语句之后,执行到该函数时的当前时间值; -- 也正因为有这个区别,我们一般在执行语句的时候,都是用NOW(),因为SYSDATE获取当时实时的时间,这有可能导致主库和从库是执行的返回值是不一样的,导致主从数据不一致。 SELECT NOW(),SLEEP(3),NOW(); -- 2018-08-16 19:03:51,0,2018-08-16 19:03:51 SELECT SYSDATE(),SLEEP(3),SYSDATE();-- 2018-08-16 19:03:54,0,2018-08-16 19:03:57 SELECT DATE_FORMAT(CURDATE(),'%w'); -- 获取今天是星期几,返回阿拉伯数字,这个准确 SELECT DAYOFWEEK(CURDATE()); -- 返回今天是星期几(1=星期天,2=星期一,……7=星期六,ODBC标准),这个不准确 SELECT WEEKDAY(CURDATE()); -- 返回今天是星期几(0=星期一,1=星期二,……6= 星期天),这个不准确 SELECT DAYOFMONTH(CURDATE()); -- 返回今天是当月中的第几日(在1到31范围内) SELECT DAYOFYEAR(CURDATE()); -- 返回今天是当年中的第几日(在1到366范围内) SELECT MONTH(CURDATE()); -- 11 返回当前月份 SELECT DAYNAME(CURDATE()); -- Friday 按英文名返回今天是星期几 SELECT MONTHNAME(CURDATE()); -- November 按英文名返回当月是几月份 SELECT QUARTER(CURDATE()); -- 返回现在的第几季度 SELECT WEEK(CURDATE()); -- 46 这个不准确 SELECT YEAR(CURDATE()); -- 2019 SELECT YEARWEEK(CURDATE()); -- 201946 这个不准确 SELECT WEEKOFYEAR(CURDATE());-- 47 这个准确 SELECT DATEDIFF(CURDATE(),'1989-10-23') -- 两个日期之间的天数差 SELECT TIMESTAMPDIFF(SECOND,'2019-11-11',SYSDATE()); -- 两个日期相差多少时间,秒或者分之类的 -- 第三个参数不仅可以是DAY,还可以是MONTH, YEAR,代表加减一个月,一年 SELECT DATE_SUB('2018-05-01',INTERVAL 1 DAY); -- 定义日期减一天 SELECT DATE_SUB(CURDATE(),INTERVAL 1 DAY); -- 当前日期减一天 SELECT DATE_SUB('2018-05-01',INTERVAL -1 DAY); -- 如果为负数的话,负负得正 SELECT DATE_ADD('2018-05-01',INTERVAL 1 MONTH); -- 输出2018-06-01 SELECT DATE_ADD(CURDATE(),INTERVAL 9 HOUR); -- 查询当天早上9点 -- 注意,这三个是一样的 SELECT SUBDATE(CURDATE(),INTERVAL 7 DAY); SELECT SUBDATE(CURDATE(),7); SELECT DATE_SUB(CURDATE(),INTERVAL 7 DAY); SELECT STR_TO_DATE(NOW(),'%Y-%m-%d %H:%i:%s') -- 字符串转日期:2017-12-29 23:59:14 SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %T') -- 日期转字符串:%T 二十四小时制:2017-12-29 23:59:46 SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %r') -- 日期转字符串:%r 十二小时制:2017-12-30 12:00:00 AM SELECT DATE('2017-12-29 11:58:54 PM') -- 返回日期或日期时间表达式的日期部分:2017-12-29 SELECT DATE_FORMAT(CURDATE(),'%Y-%m-%d 00:00:00');-- 获取当天零点零分零秒;其实如果字段类型是date类型的话,就默认当天零点零分了 SELECT DATE_FORMAT(CURDATE(),'%Y-%m-%d 23:59:59');-- 。。。。。。 SELECT SUBDATE(CURDATE(),(WEEKDAY(CURDATE()) + 7)); -- 上个星期一的日期 SELECT SUBDATE(CURDATE(),(WEEKDAY(CURDATE()) + 1)); -- 上个星期天的日期 SELECT SUBDATE(CURDATE(),WEEKDAY(CURDATE())); -- 这个星期一的日期 SELECT SUBDATE(CURDATE(),(WEEKDAY(CURDATE()) - 6)); -- 这个星期天的日期 SELECT DATE_SUB(SUBDATE(CURDATE(),(DAYOFMONTH(CURDATE())-1)),INTERVAL 1 MONTH); -- 上个月第一天 SELECT SUBDATE(CURDATE(),DAYOFMONTH(CURDATE())); -- 上个月最后一天
处理字符串:
SELECT CONCAT('aa','bb','cc') -- 将aa,bb,cc连接成字符串 SELECT CONCAT_WS('-','aa','bb','cc') -- 将aa,bb,cc连接成字符串,并用'-'隔开 SELECT INSERT('郭晓锋你好',2,3,'郭辉') -- 将被替换字符串'郭晓锋',从第2个开始(晓),截取3个长度(晓锋你),替换成'郭晓辉' SELECT LOWER('AAABc') -- 变小写 SELECT LCASE('AAABc') -- 变小写 SELECT UPPER('AAABc') -- 变大写 SELECT UCASE('AAABc') -- 变大写 SELECT LEFT('12345',3) -- 123 SELECT RIGHT('12345',3) -- 345 SELECT LENGTH('12345') -- 5 SELECT POSITION('a' IN '345ababc') -- 前面那个字符串在后面出现的位置 SELECT REVERSE('123456') -- 颠倒字符串 SELECT TRIM('asd ') -- 去掉空格,LTRIM(),RTRIM() SELECT SUBSTRING('12345678',2,3) -- 被截取字符串从第二位开始,截取三位长度,也就是变成了'234';其实,SUBSTR也可以 SELECT SUBSTRING('12345678',2) -- 如果没有写截取的长度,则截取全部,变成了'2345678';其实,SUBSTR也可以 SELECT REPLACE('2015-01','-','') -- 变成了 '201501' SELECT REPEAT('str',4) -- 返回从字符串str x 位置起y 个字符长度的字串,结果为:strstrstrstr select lpad('2008',20,'beijing'),rpad('beijing',20,'2008'); -- beijingbeijingbe2008,beijing2008200820082 select replace('beijing2010','2010','2008'); -- 用2008替换2010 SELECT SUBSTRING_INDEX('blog.jb51.net','.',1); -- blog SELECT SUBSTRING_INDEX('blog.jb51.net','.',2); -- blog.jb51 SELECT SUBSTRING_INDEX('blog.jb51.net','.',-1);-- net SELECT SUBSTRING_INDEX('blog.jb51.net','.',-2);-- jb51.net
UNION 和UNION ALL 的主要区别:
UNION ALL 是把结果集直接合并在一起,而UNION 是将UNION ALL 后的结果进行一次DISTINCT,去除重复记录后的结果。(注意,两个select语句返回的字段名一定要是一样的)
处理数字:
select ABS(-0.8) ,ABS(0.8); -- 返回绝对值 SELECT CEIL(1.8),CEIL(-1.8) -- 返回大于1.8的最大整数,里面要是小数啊 SELECT FLOOR(1.8),FLOOR(-1.8) -- 返回小于1.8的最大整数,里面要是小数啊 SELECT MOD(5,3) -- 取模 SELECT RAND() -- 0到1之间随机值 SELECT CEIL(100 * RAND()) -- 0到100之间随机整数 SELECT ROUND(23.1284,2) -- 四舍五入2位小数值 SELECT TRUNCATE(23.1284,2) -- 截断 ,剩两位小数 -- 关于数字拼接的特殊性 SELECT '1' + '-'; -- 1 SELECT '1' + '2'; -- 3 SELECT '1' + '-' + '2'; -- 3 SELECT CONCAT('1','2'); -- 12 SELECT CONCAT('1','-','2'); -- 12
删除重复值(只保留一个)
-- 不能: DELETE FROM testa WHERE ID NOT IN ( (SELECT MAX(ID) AS ID FROM testa GROUP BY `name`) ) -- mysql中You can't specify target table for update in FROM clause错误的意思是说,不能先select出同一表中的某些值,再update这个表(在同一语句中)。注意,这个问题只出现于mysql,mssql和oracle不会出现此问题。 -- 这样(用临时表): DELETE FROM testa WHERE ID NOT IN ( SELECT a.ID FROM ( (SELECT MAX(ID) AS ID FROM testa GROUP BY `name`) )a )
关于IF以及NULL
SELECT (CASE WHEN t.empno = 7844 -- 这样写的话,可以大于号小于号等等 THEN (SELECT empno FROM emp WHERE emp_id = '11') ELSE (SELECT empno FROM emp WHERE emp_id = '12') END) FROM (SELECT empno FROM emp WHERE emp_id = '00' )t -- ------------------------------------------------- SELECT (CASE t.empno WHEN 7844 -- 这样写的话,相当于 t.empno = 7844 THEN (SELECT empno FROM emp WHERE emp_id = '11') ELSE (SELECT empno FROM emp WHERE emp_id = '12') END) FROM (SELECT empno FROM emp WHERE emp_id = '00' )t -- ------------------------------------------------- SELECT IF(t.empno = 7844, (SELECT empno FROM emp WHERE emp_id = '11'), (SELECT empno FROM emp WHERE emp_id = '12') ) FROM (SELECT empno FROM emp WHERE emp_id = '00' )t -- -------------------------------------------------------- SELECT ISNULL(NULL); -- 如果是空值的话就为1(true),如果不是空值的话就为0(false) SELECT IFNULL(1,2); -- 如果1不为空值的话,就返回1,如果1为空值的话,就返回2 SELECT NULLIF(1,1) -- 如果两个值相等的话,就返回null,否则返回第一个数字 -- 判断是否存在该记录,直接取得总条数就可以了啊,哈哈,这个疑问之前困扰了我一天,所以干事情一定要多思考啊
-- 是否存在着该条记录,如果存在着该记录,则干某事,否则干某事 SELECT IF(t.count = 0, (SELECT empno AS count FROM emp WHERE emp_id = '11'), (SELECT empno AS count FROM emp WHERE emp_id = '12') ) FROM (SELECT COUNT(*) AS count FROM emp WHERE emp_id = '005')t
timestamp 以及 datetime 类型:
1、如果需要经常插入或者更新日期为当前系统时间,则通常使用TIMESTAMP 来表示; 2、TIMESTAMP 值返回后显示为“YYYY-MM-DD HH:MM:SS”格式的字符串,显示宽度固定为19 个字符; 3、timestamp 那里的默认值可以写上 CURRENT_TMIESTAMP 来表示默认当前时间,其实这个是挺好用的; 4、TIMESTAMP的取值范围为19700101080001到2038年的某一天,因此它不适合存放比较久远的日期(当插入的值超出取值范围时,MySQL认为该值溢出,使用“0000-00-00 00:00:00”进行填补。),而DATETIME是从1000-01-01 00:00:00到9999-12-31 23:59:59,范围更大; 5、TIMESTAMP 主要存放跟时区有关的啊,时区,是时区啊,TIMESTAMP的插入和查询都受当地时区的影响,更能反应出实际的日期。而DATETIME则只能反应出插入时当地的时区,其他时区的人查看数据必然会有误差
更新一个数据表里面的字段值为另外一个:
-- 之前是这样写的,用子查询,不过这样不好 UPDATE tm_esim_manual_account ma SET work_place = (SELECT workplace_base_name FROM tm_esim_workplace_base wp WHERE wp.workplace_base_code = ma.work_place) -- 用连接查询这样会更好,也看得更明白 UPDATE tm_esim_manual_account ma INNER JOIN tm_city_code cc ON ma.work_place = cc.city_name SET ma.pay_city= cc.city_id
级联删除(级联之后,只删除其中一个表啊,注意别名):
DELETE tp FROM test_person tp INNER JOIN cao_test ct ON tp.id = ct.id WHERE ct.haha = '222';
替换字段里面的某一个值里面特定的字符串成另外的:
UPDATE `tm_esim_insurance_combine_maintenance` SET insurance_combine = REPLACE(insurance_combine,')',')')
SUBSTRING_INDEX,GROUP_CONCAT,ORDER BY,GROUP BY 的综合使用(GROUP BY之后的里面的GROUP_CONCAT,用ORDER BY字段排序,然后通过SUBSTRING_INDEX截取里面的相关字段,秒)
SELECT SUBSTRING_INDEX(GROUP_CONCAT(t.id ORDER BY t.stats DESC, t.modifier_time DESC),',',1) AS id, t.socurity_accum_account, SUBSTRING_INDEX(GROUP_CONCAT(t.company_socur_accumAcc ORDER BY t.stats DESC,t.modifier_time DESC),',',1) AS company_socur_accumAcc FROM tm_esim_sociala_mainte t WHERE t.effective_date <= CURDATE() GROUP BY t.socurity_accum_account
案例:自定义排序,例如,在emp表中,根据:MANAGER,ANALYST,SALESMAN这几个字段来升序排列:
SELECT * FROM emp ORDER BY (CASE job WHEN 'MANAGER' THEN '0' WHEN 'ANALYST' THEN '1' WHEN 'SALESMAN' THEN '2' ELSE 3 END);
求交叉区间,即是说:输入的时间区间同数据库的时间区间不能有交叉,有交叉,则返回数据。这个在工作中的一个项目应用十分强,开始不知道这个,如果开始知道这个的话,就不用走那么多弯路了;
-- 数据库的开始时间大于输入来的结束时间,或者数据库的结束时间小于输入来的开始时间,这两种情况下,则无交叉,求反集,即是有交叉的了;这里的应用主要是NOT NOT NOT 啊 SELECT * FROM country WHERE NOT (begin_date > '2018-05-25' OR end_date < '2018-05-01')
更新在今天之前的某些数据(如果这个语句早知道,那样的话在工作中就少些很多垃圾代码了)(其实工作中的很多代码,都可以用连接查询代替子查询的了):
-- 后来的一开始是这样写的: UPDATE table_01 SET status_a = 1 WHERE valid_date < CURDATE() AND status_a = 0 AND insurance_combine IN ( SELECT t.insurance_combine FROM ( SELECT icm.insurance_combine FROM table_01 icm WHERE icm.status_a = 0 AND icm.valid_date = date_format(NOW(),'%y-%m-%d') GROUP BY id )t ); -- 但是用子查询的效率比不上连接查询的效率高: UPDATE table_01 t1 INNER JOIN (SELECT icm.insurance_combine FROM table_01 icm WHERE icm.status_a = 0 AND icm.valid_date = date_format(NOW(),'%y-%m-%d') GROUP BY id)t2 ON t1.insurance_combine = t2.insurance_combine SET t1.status_a = 1 WHERE t1.valid_date < CURDATE() AND t1.status_a = 0
发现新大陆(批量更新):
UPDATE cao_dept SET dept = (CASE id WHEN '11' THEN '1111' WHEN '22' THEN '2222' WHEN '33' THEN '3333' WHEN '44' THEN '4444' ELSE '' END) WHERE id IN ('11','22','33','44')
END!
SELECT h.value AS item_value, h.itemid
FROM history AS h
RIGHT JOIN (SELECT itemid, MAX(clock) AS clock FROM history GROUP BY itemid) AS m
ON h.itemid=m.itemid AND h.clock=m.clock