MySQL脚本

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
原文地址:https://www.cnblogs.com/ericguoxiaofeng/p/8098508.html