SQL语句

Posted 天马行空郭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL语句相关的知识,希望对你有一定的参考价值。

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:\\ProgramData\\MySQL\\MySQL Server 8.0\\Data\\

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 < \'以上是关于SQL语句的主要内容,如果未能解决你的问题,请参考以下文章

MYBATIS05_ifwherechoosewhentrimsetforEach标签sql片段

动态SQL基础概念复习(Javaweb作业5)

Mybatis超强大的动态SQL大全

mybatis学习日志二

使用 with as 优化SQL

Mybatis超强大的动态SQL大全