mysql笔记
一:sql语言分类
1.DDL:数据定义语言
create、alter、drop、rename、truncate
2.DML:数据操作语言
insert、delete、upate、select
3.DCL:数据控制语言
commit、rollback、savepoint、grant、revoke
二:基本规则
1.每条命令以;或者\g或者\G结束
2.命令过长可以分行写
3.关于标点符号
4.mysql在windows环境下大小写不敏感
在linux下敏感
5.统一书写规范
6.注释
7.命令行导入数据库-------->命令行执行
source:绝对路径;
三:基本语句
1.select * from table;
列的别名
SELECT id,name,age as age1 FROM USER;//as
SELECT id,name,age age1 FROM USER;//加空格
SELECT id,name,age "age1" FROM USER;//双引号,不要使用单引号
#结果中age属性更换名称叫age1
去除重复行(distinct)---->一般只能查一个的时候去重
SELECT DISTINCT age FROM user
空值参与运算----解决方案:用函数
着重号
当表名或者字段名与保留字重名时,加单引号,即着重号表示这不是保留字
查询常数
SELECT '公司名',name,age,FROM user;
常数的意思是在此处插入一列数据,全部为所写的数据
显示表结构
DESCRIBE TABLE;显示了表中字段的详细信息(或简写DESC table)
过滤数据
SELECT * FROM WHERE id = 1;
2.运算符
1.基本运算符
+ - / * div % mod---->只能代表基本运算,没有其他语言中的作用
SELECT 100 + 1 FROM DUAL;#101
SELECT 100 + '1' FROM DUAL;#101,会将字符转换成数值
SELECT 100 + 'a' FROM DUAL;#100,不可转换的字符看错0
SELECT 100 + NULL FROM DUAL;#100,null=0
SELECT 100 / 5 FROM DUAL;#20.0除法结果一定是浮点型
SELECT 100 / 5.0 FROM DUAL;#20.0
SELECT 100 / 3 FROM DUAL;#33.3333,结果为小数
SELECT 100 DIV 0 FROM DUAL;#分母为0,结果为NULL,但是数学中不成立
2.取模运算
SELECT 100 % 3,-12 % -5 FROM DUAL;#1,-2,符号与被除数一样
3.比较运算符
= <=>安全等于 <>(!=)不等于 < > >=
IS NULL IS NOTNULL LEAST最小值 GREATEST最大值 betwen and ISNULL IN NOT IN
LIKE REGEXP ESCAPE REGEXP
- 字符串直接不存在隐式转换,比较是直接比较ASCII码 ‘a’=‘b’ —>0
- 只要有null参与判断,结果为null 1=null---->null
- slect name from user where sex=null;结果为空,不会有任何结果
- <=>跟=的区别就是可以与null做运算;select 1<=>null,null=null from dual;结果为0 1
- select 3<>2 ,‘4’<>null,‘’!=null from dual;#1 null null
- select name from user where name like ‘%a%’;#模糊查询;‘a%’ a开头,‘%a’ a结尾,'_a%'第二个是a
ESCAPE
回避特殊符号的:使用转义符。例如:将[%]转为[
%]、[]转为[
],然后再加上[ESCAPE‘$’]即可
SELECT job_id
FROM jobs
WHERE job_id LIKE ‘IT\_%‘;
如果使用\表示转义,要省略ESCAPE。如果不是\,则要加上ESCAPE。
SELECT job_id
FROM jobs
WHERE job_id LIKE ‘IT$_%‘ escape ‘$‘;
REGEXP运算符用来匹配字符串,语法格式为: expr REGEXP 匹配条件 。如果expr满足匹配条件,返回
(1)‘^’匹配以该字符后面的字符开头的字符串。
(2)‘$’匹配以该字符前面的字符结尾的字符串。
(3)‘.’匹配任何一个单字符。
(4)“[...]”匹配在方括号内的任何字符。例如,“[abc]”匹配“a”或“b”或“c”。为了命名字符的范围,使用一
个‘-’。“[a-z]”匹配任何字母,而“[0-9]”匹配任何数字。
(5)‘*’匹配零个或多个在它前面的字符。例如,“x*”匹配任何数量的‘x’字符,“[0-9]*”匹配任何数量的数字,
而“*”匹配任何数量的任何字符
mysql> SELECT 'shkstart' REGEXP '^s', 'shkstart' REGEXP 't$', 'shkstart' REGEXP 'hk';
| 'shkstart' REGEXP '^s' | 'shkstart' REGEXP 't$' | 'shkstart' REGEXP 'hk' |
| 1 | 1 | 1 |
1 row in set (0.01 sec)
mysql> SELECT 'atguigu' REGEXP 'gu.gu', 'atguigu' REGEXP '[ab]';
| 'atguigu' REGEXP 'gu.gu' | 'atguigu' REGEXP '[ab]' |
| 1 | 1 |
4.逻辑运算符
1.NOT 或者 !
2.AND 或者 &&
3.OR 或者 ||
4.XOR异或,当两边一真一假时,成立
5.位运算符
3.排序与分页
1.排序
order by—>默认升序
列的别名不可以在where中使用,只可以在order by中使用
- ASC(ascend): 升序
- DESC(descend):降序
- ORDER BY 子句在SELECT语句的结尾。ASC(ascend): 升序
- DESC(descend):降序
- ORDER BY 子句在SELECT语句的结尾。
SELECT last_name, job_id, department_id, hire_date
FROM employees
ORDER BY hire_date DESC ;
SELECT employee_id,salary,department_id
FROM employee
ORDER BY department_id DESC,salary ASC;
#可以使用不在SELECT列表中的列排序。
#在对多列进行排序的时候,首先排序的第一列必须有相同的列值,才会对第二列进行排序。如果第
#一列数据中所有值都是唯一的,将不再对第二列进行排序。
2.分页
LIMIT [位置偏移量,] 行数----->注意:LIMIT 子句必须放在整个SELECT语句的最后!
查询特定某页
--前10条记录:
SELECT * FROM 表名 LIMIT 0,10;
或者
SELECT * FROM 表名 LIMIT 10;
--第11至20条记录:
SELECT * FROM 表名 LIMIT 10,10;
#MySQL 8.0中可以使用“LIMIT 3 OFFSET 4”,意思是获取从第5条记录开始后面的3条记录,和“LIMIT
4,3;”返回的结果相同。
#公式:
SELECT * FROM table
LIMIT(PageNo - 1)*PageSize,PageSize;
查询具体某些条信息
#查询第32,33条信息
SELECT employee_id,salary,department_id
FROM employees
LIMIT 2 OFFSET 31
#查询工资最高的信息
SELECT employee_id,salary,department_id
FROM employees
ORDER BY salary DESC
LIMIT 1;
或者
SELECT employee_id,salary,department_id
FROM employees
LIMIT 31,2;#mysql8.0中2与31需要换位置,这是两者区别
4.多表查询
1.查询多个表
将不同表之间,用 id 相互联系,多表之间,需要有连接条件;如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。
n个表,则至少有n-1个连接条件
#案例:查询员工的姓名及其部门名称
SELECT last_name, department_name
FROM employees, departments
WHERE employees.department_id = departments.department_id;
2.多表查询的分类
1.等值连接 vs 非等值连接
-
非等值连接
select * from job
SELECT e.last_name,e.salary,j.grade_level FROM employees e,hob_grades j WHERE e.salary between j.lowest_sal and j.highest_sal; #WHERE e.salary >= jlowest_sal AND e.salary <= j.highest_sal
2.自连接 vs 非自连接
-
练习:查询员工id,姓名及其管理者的id和姓名
-
自连接指自己跟自己连接
SELECT emp.employee_id, emp.last_name,mgr.employee_id,mgr.last_name FROM employees emp,employees mgr WHERE emp.magager_id = mgr.employee_id;
3.内连接 vs 外连接
-
内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
SELECT last_name, department_name FROM employees, departments WHERE employees.department_id = departments.department_id;
-
外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的
行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。 -
如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 。
-
如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表 。
-
SQL92连接—>mysql不支持
#左外连接 SELECT last_name,department_name FROM employees ,departments WHERE employees.department_id = departments.department_id(+); #右外连接 SELECT last_name,department_name FROM employees ,departments WHERE employees.department_id(+) = departments.department_id;
而且在 SQL92 中,只有左外连接和右外连接,没有满(或全)外连接。
-
SQL99连接---->使用join…on------>mysql支持
#内连接 SELECT last_name,department_name,city FROM employees e JOIN departments d ON e.departments_id=d.departments_id #JOIN ON 可以无限叠加
#外连接 SELECT lase_name,department_name FROM employee e LEFT OUTER JOIN department d ON e.departments_id=d.departments_id #LEFT 改为RIGHT为右外连接
#满外连接---->mysql不支持 SELECT lase_name,department_name FROM employee e FULL OUTER JOIN department d ON e.departments_id=d.departments_id
4.UNION操作符
合并查询结果 利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并
时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNION或UNION
ALL关键字分隔。
-
SELECT column,... FROM table1 UNION [ALL] SELECT column,... FROM table2
-
UNION 操作符返回两个查询的结果集的并集,去除重复记录。
-
UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。
-
注意:执行UNION ALL语句时所需要的资源比UNION语句少。如果明确知道合并数据后的结果数据
不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效
率。 -
#举例:查询部门编号>90或邮箱包含a的员工信息 SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90; SELECT * FROM employees WHERE email LIKE '%a%' UNION SELECT * FROM employees WHERE department_id>90; #举例:查询中国用户中男性的信息以及美国用户中年男性的用户信息 SELECT id,cname FROM t_chinamale WHERE csex='男' UNION ALLs SELECT id,tname FROM t_usmale WHERE tGender='male';
5.SQL99的外连接七种语法
-
中图:内连接
#查询所有员工的部门,没有部门的不算 SELECT employee_id,department_name FROM employees e JOIN department d ON e.department_id=d.department_id;
-
左上图:左外连接
#查询所有员工的部门,没有部门的也算 SELECT e.employee_id,d.department_name FROM employees e LEFT JOIN departments d ON e.department_id=d.department_id;
-
右上图:右外连接
#查询所有部门所拥有的每一位员工信息,没有员工的部门也算一条记录 SELECT e.employee_id,d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id=d.department_id;
-
左中图
#查询没有部门的员工 SELECT e.employee_id,d.department_name FROM employees e LEFT JOIN departments d ON e.department_id=d.department_id WHERE d.department_id IS NULL
-
右中图
#查询所有部门没有员工的部门 SELECT e.employee_id,d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id=d.department_id WHERE e.employee_id IS NULL
-
左下图:满外连接
#方式一(左上 + UNION ALL + 右中) SELECT e.employee_id,d.department_name FROM employees e LEFT JOIN departments d ON e.department_id=d.department_id UNION ALL SELECT e.employee_id,d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id=d.department_id WHERE e.employee_id IS NULL #方式二(左中图 + UNION ALL + 右上图) SELECT e.employee_id,d.department_name FROM employees e LEFT JOIN departments d ON e.department_id=d.department_id WHERE d.department_id IS NULL UNION ALL SELECT e.employee_id,d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id=d.department_id;
-
右下图:
#左中+右中 SELECT e.employee_id,d.department_name FROM employees e LEFT JOIN departments d ON e.department_id=d.department_id WHERE d.department_id IS NULL UNION ALL SELECT e.employee_id,d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id=d.department_id WHERE e.employee_id IS NULL
6.SQL99的新特性
1.自然连接NATURE JOIN
自然连接可以理解成SQL92中的等值连接,它会自动查询两张连接表中所有相同的字段,然后进行等值连接
SELECT employee_id,last_name,department_name
FROM emloyee e JOIN department d
ON e.department_id=d.department_id
ANDe.department_id=d.manger_id
#与下面一样的
SELECT employee_id,last_name,deoartment_name
FROM employee e NATURE JOIN department d;
2.USING
使用USING指定数据库表中同名字段进行等值连接,但是只能配合JOIN ON一起使用。不适用与自连接
SELECT employee_id,last_name,department_name
FROM employee e JOIN department d
ON e.department_id=d.department_id;
#使用using
SELECT employee_id,last_name,department_name
FROM employee e JOIN department d
USERING(department_id)
3.小总结
表连接约束条件可以右三种方式WHERE ON USING
- WHERE: 适用于所有关联查询
- ON:只能和JOIN一起使用,只能写关联条件,虽然关联条件可以和where一起写,但是分开可读性更好
- USING只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字段值相等
5单行函数
1.数值函数
ABS(x) 返回x的绝对值
SIGN(X) 返回X的符号。正数返回1,负数返回-1,0返回0
PI() 返回圆周率的值
CEIL(x),CEILING(x) 返回大于或等于某个值的最小整数
FLOOR(x) 返回小于或等于某个值的最大整数
LEAST(e1,e2,e3…) 返回列表中的最小值
GREATEST(e1,e2,e3…****) 返回列表中的最大值
MOD(x,y) 返回X除以Y后的余数
RAND() 返回0~1的随机值
**RAND(x)**返回0~1的随机值,其中x的值用作种子值,相同的X值会产生相同的随机
数
ROUND(x) 返回一个对x的值进行四舍五入后,最接近于X的整数
ROUND(x,y) 返回一个对x的值进行四舍五入后最接近X的值,并保留到小数点后面Y位
TRUNCATE(x,y) 返回数字x截断为y位小数的结果
SQRT(x) 返回x的平方根。当X的值为负数时,返回NULL
RADIANS(x) 将角度转化为弧度,其中,参数x为角度值
DEGREES(x) 将弧度转化为角度,其中,参数x为弧度值
SELECT
ABS(-123),ABS(32),SIGN(-23),SIGN(43),PI(),CEIL(32.32),CEILING(-43.23),FLOOR(32.32),
FLOOR(-43.23),MOD(12,5)
FROM DUAL;
SELECT RAND(),RAND(),RAND(10),RAND(10),RAND(-1),RAND(-1)
FROM DUAL;
SELECT
ROUND(12.33),ROUND(12.343,2),ROUND(12.324,-1),TRUNCATE(12.66,1),TRUNCATE(12.66,-1)
FROM DUAL;
SELECT RADIANS(30),RADIANS(60),RADIANS(90),DEGREES(2*PI()),DEGREES(RADIANS(90))
FROM DUAL;
2.三角函数
SIN(x) 返回x的正弦值,其中,参数x为弧度值
ASIN(x) 返回x的反正弦值,即获取正弦为x的值。如果x的值不在-1到1之间,则返回NULL
COS(x) 返回x的余弦值,其中,参数x为弧度值
ACOS(x) 返回x的反余弦值,即获取余弦为x的值。如果x的值不在-1到1之间,则返回NULL
TAN(x) 返回x的正切值,其中,参数x为弧度值
ATAN(x) 返回x的反正切值,即返回正切值为x的值
ATAN2(m,n) 返回两个参数的反正切值
COT(x) 返回x的余切值,其中,X为弧度值
SELECT
SIN(RADIANS(30)),DEGREES(ASIN(1)),TAN(RADIANS(45)),DEGREES(ATAN(1)),DEGREES(ATAN2(1,1)
)
FROM DUAL;
**POW(x,y),**POWER(X,Y) 返回x的y次方
EXP(X) 返回e的X次方,其中e是一个常数,2.718281828459045
**LN(X),**LOG(X) 返回以e为底的X的对数,当X <= 0 时,返回的结果为NULL
LOG10(X) 返回以10为底的X的对数,当X <= 0 时,返回的结果为NULL
LOG2(X) 返回以2为底的X的对数,当X <= 0 时,返回NULL
SELECT POW(2,5),POWER(2,4),EXP(2),LN(10),LOG10(10),LOG2(4)
FROM DUAL;
3.进制转换
BIN(x) 返回x的二进制编码
HEX(x) 返回x的十六进制编码
OCT(x) 返回x的八进制编码
CONV(x,f1,f2) 返回f1进制数变成f2进制数
SELECT BIN(10),HEX(10),OCT(10),CONV(10,2,8)
FROM DUAL;
4.字符串函数
ASCII(S) 返回字符串S中的第一个字符的ASCII码值
CHAR_LENGTH(s) 返回字符串s的字符数。作用与CHARACTER_LENGTH(s)相同
LENGTH(s) 返回字符串s的字节数,和字符集有关
CONCAT(s1,s2,…,sn) 连接s1,s2,…,sn为一个字符串
**CONCAT_WS(x,s1,s2,…,sn)**同CONCAT(s1,s2,…)函数,但是每个字符串之间要加上x
**INSERT(str, idx, len,replacestr)**将字符串str从第idx位置开始,len个字符长的子串替换为字符串replacestr
REPLACE(str, a, b) 用字符串b替换字符串str中所有出现的字符串a
UPPER(s) 或 UCASE(s) 将字符串s的所有字母转成大写字母
LOWER(s) 或LCASE(s) 将字符串s的所有字母转成小写字母
LEFT(str,n) 返回字符串str最左边的n个字符
RIGHT(str,n) 返回字符串str最右边的n个字符
LPAD(str, len, pad) 用字符串pad对str最左边进行填充,直到str的长度为len个字符
RPAD(str ,len, pad) 用字符串pad对str最右边进行填充,直到str的长度为len个字符
LTRIM(s) 去掉字符串s左侧的空格
RTRIM(s) 去掉字符串s右侧的空格
TRIM(s) 去掉字符串s开始与结尾的空格
TRIM(s1 FROM s) 去掉字符串s开始与结尾的s1
**TRIM(LEADING s1FROM s)**去掉字符串s开始处的s1
**TRIM(TRAILING s1FROM s)**去掉字符串s结尾处的s1
REPEAT(str, n) 返回str重复n次的结果
SPACE(n) 返回n个空格
STRCMP(s1,s2) 比较字符串s1,s2的ASCII码值的大小
**SUBSTR(s,index,len)返回从字符串s的index位置其len个字符,作用与SUBSTRING(s,n,len)、*MID(s,n,len)***相同
**LOCATE(substr,str)返回字符串substr在字符串str中首次出现的位置,作用于POSITION(substrIN str)、INSTR(str,substr)**相同。未找到,返回0
ELT(m,s1,s2,…,sn)
返回指定位置的字符串,如果m=1,则返回s1,如果m=2,则返回s2,如
果m=n,则返回sn
FIELD(s,s1,s2,…,sn) 返回字符串s在字符串列表中第一次出现的位置
SELECT
ABS(-123),ABS(32),SIGN(-23),SIGN(43),PI(),CEIL(32.32),CEILING(-43.23),FLOOR(32.32),
FLOOR(-43.23),MOD(12,5)
FROM DUAL;
SELECT RAND(),RAND(),RAND(10),RAND(10),RAND(-1),RAND(-1)
FROM DUAL;
SELECT ROUND(12.33),ROUND(12.343,2),ROUND(12.324,-1),TRUNCATE(12.66,1),TRUNCATE(12.66,-1),SQRT(-5)
FROM DUAL;
SELECT RADIANS(30),RADIANS(60),RADIANS(90),DEGREES(2*PI()),DEGREES(RADIANS(90))
FROM DUAL;
SELECT
SIN(RADIANS(30)),DEGREES(ASIN(1)),TAN(RADIANS(45)),DEGREES(ATAN(1)),DEGREES(ATAN2(1,1))
FROM DUAL;
SELECT POW(2,5),POWER(2,4),EXP(2),LN(10),LOG10(10),LOG2(4)
FROM DUAL;
SELECT BIN(100),HEX(100),OCT(100),CONV(100,10,8)
FROM DUAL;
SELECT repeat('+helloword',3 ),LOCATE('o','helloword')
FROM DUAL;
SELECT FIELD('mm','hello','mm','amma'),FIND_IN_SET('mm','hello,mm,amma')
FROM DUAL;
SELECT REVERSE('HELLOWORD')
FROM DUAL;
SELECT NULLIF(1,2)
FROM DUAL;
5.日期函数
1. 获取日期、时间
**CURDATE() ,CURRENT_DATE()**返回当前日期,只包含年、月、日
**CURTIME() , CURRENT_TIME()**返回当前时间,只包含时、分、秒
NOW() / SYSDATE() / CURRENT_TIMESTAMP() / LOCALTIME() /
**LOCALTIMESTAMP()**返回当前系统日期和时间
**UTC_DATE()**返回UTC(世界标准时间)日期
**UTC_TIME()**返回UTC(世界标准时间)时间
2 日期与时间戳的转换
**UNIX_TIMESTAMP()**以UNIX时间戳的形式返回当前时间。SELECT UNIX_TIMESTAMP() ->1634348884
UNIX_TIMESTAMP(date) 将时间date以UNIX时间戳的形式返回。
FROM_UNIXTIME(timestamp) 将UNIX时间戳的时间转换为普通格式的时间
3. 获取月份、星期、星期数、天数等函数
YEAR(date) / MONTH(date) / DAY(date) 返回具体的日期值
**HOUR(time) / MINUTE(time) /SECOND(time)**返回具体的时间值
MONTHNAME(date) 返回月份:January,…
DAYNAME(date) 返回星期几:MONDAY,TUESDAY…SUNDAY
WEEKDAY(date) 返回周几,注意,周1是0,周2是1,。。。周日是6
QUARTER(date) 返回日期对应的季度,范围为1~4
WEEK(date) , WEEKOFYEAR(date) 返回一年中的第几周
DAYOFYEAR(date) 返回日期是一年中的第几天
DAYOFMONTH(date) 返回日期位于所在月份的第几天
**DAYOFWEEK(date)**返回周几,注意:周日是1,周一是2,。。。周六是7
EXTRACT(type FROM date) 返回指定日期中特定的部分,type指定返回的值
SELECT EXTRACT(MINUTE FROM NOW()),EXTRACT( WEEK FROM NOW()),
EXTRACT( QUARTER FROM NOW()),EXTRACT( MINUTE_SECOND FROM NOW())
FROM DUAL;
5 时间和秒钟转换的函数
**TIME_TO_SEC(time)**将 time 转化为秒并返回结果值。转化的公式为: 小时3600+分钟60+秒
SEC_TO_TIME(seconds) 将 seconds 描述转化为包含小时、分钟和秒的时间
6 计算日期和时间的函数
**DATE_ADD(datetime, INTERVAL expr type),ADDDATE(date,INTERVAL expr type)**返回与给定日期时间相差INTERVAL时间段的日期时间
**DATE_SUB(date,INTERVAL expr type),SUBDATE(date,INTERVAL expr type)**返回与date相差INTERVAL时间间隔的日期
ADDDATE('2021-10-21 23:32:12',INTERVAL 1 SECOND) AS col3,
DATE_ADD('2021-10-21 23:32:12',INTERVAL '1_1' MINUTE_SECOND) AS col4,
DATE_ADD(NOW(), INTERVAL -1 YEAR) AS col5, #可以是负数
DATE_ADD(NOW(), INTERVAL '1_1' YEAR_MONTH) AS col6 #需要单引号
FROM DUAL;
SELECT DATE_SUB('2021-01-21',INTERVAL 31 DAY) AS col1,
SUBDATE('2021-01-21',INTERVAL 31 DAY) AS col2,
DATE_SUB('2021-01-21 02:01:01',INTERVAL '1 1' DAY_HOUR) AS col3
FROM DUAL;
SELECT
ADDTIME(NOW(),20),SUBTIME(NOW(),30),SUBTIME(NOW(),'1:1:3'),DATEDIFF(NOW(),'2021-10-
01'),
TIMEDIFF(NOW(),'2021-10-25 22:10:10'),FROM_DAYS(366),TO_DAYS('0000-12-25'),
LAST_DAY(NOW()),MAKEDATE(YEAR(NOW()),12),MAKETIME(10,21,23),PERIOD_ADD(20200101010101,
10)
FROM DUAL;
7 日期的格式化与解析
SELECT DATE_FORMAT(NOW(), '%H:%i:%s');
| DATE_FORMAT(NOW(), '%H:%i:%s') |
| 22:57:34
6流程控制函数
IF(value,value1mvable2)–>value是true,返回value1,否则返回value2
SELECT last_name,salary,IF(salary>=6000,'heigh','low')
FROM employees;
IFNULL(value,value1)–>value是null,返回value,否则返回value1
SELECT last_name,salary,IFNULL(department_id,'老板'),IF(salary>=6000,'heigh','low')
FROM employees;
**CASE WHEN…THEN…WHEN…**类似于if else
SELECT last_name,salary,CASE WHEN salary>=15000 THEN '1'
WHEN salary>=10000 THEN'2'
WHEN salary>=8000 THEN '3'
ELSE '4' END "detail"
FROM employees;
CASE expr WHEN …THEN… WHEN … THEN … [ELSE 值n] END–>类似于switch case
SELECT employee_id,last_name,department_id,salary,CASE department_id
WHEN 10 THEN salary*1.1
WHEN 20 THEN salary*1.2
WHEN 30 THEN salary*1.3
ELSE salary*1.4 END "detail"
FROM employees;
SELECT employee_id,last_name,department_id,salary,CASE department_id
WHEN 10 THEN salary*1.1
WHEN 20 THEN salary*1.2
WHEN 30 THEN salary*1.3
END "detail"
FROM employees
WHERE department_id IN (10,20,30);
7. 加密与解密函数
加密与解密函数主要用于对数据库中的数据进行加密和解密处理,以防止数据被他人窃取。
SELECT md5('123')
->202cb962ac59075b964b07152d234b70
mysql> SELECT DECODE(ENCODE('mysql','mysql'),'mysql');
+-----------------------------------------+
| DECODE(ENCODE('mysql','mysql'),'mysql') |
+-----------------------------------------+
| mysql |
+-----------------------------------------+
1 row in set, 2 warnings (0.00 sec)
8. MySQL信息函数
MySQL中内置了一些可以查询MySQL信息的函数,这些函数主要用于帮助数据库开发或运维人员更好地
对数据库进行维护工作。
mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| test |
+------------+
mysql> SELECT USER(), CURRENT_USER(), SYSTEM_USER(),SESSION_USER();
+----------------+----------------+----------------+----------------+
| USER() | CURRENT_USER() | SYSTEM_USER() | SESSION_USER() |
+----------------+----------------+----------------+----------------+
| root@localhost | root@localhost | root@localhost | root@localhost |
+----------------+----------------+----------------+----------------+
9.其他函数
# 如果n的值小于或者等于0,则只保留整数部分
mysql> SELECT FORMAT(123.123, 2), FORMAT(123.523, 0), FORMAT(123.123, -2);
+--------------------+--------------------+---------------------+
| FORMAT(123.123, 2) | FORMAT(123.523, 0) | FORMAT(123.123, -2) |
+--------------------+--------------------+---------------------+
| 123.12 | 124 | 123 |
+--------------------+--------------------+---------------------+
1 row in set (0.00 sec)
mysql> SELECT INET_ATON('192.168.1.100');
+----------------------------+
| INET_ATON('192.168.1.100') |
+----------------------------+
| 3232235876 |
+----------------------------+
1 row in set (0.00 sec)
mysql> SELECT CHARSET('mysql'), CHARSET(CONVERT('mysql' USING 'utf8'));
+------------------+----------------------------------------+
| CHARSET('mysql') | CHARSET(CONVERT('mysql' USING 'utf8')) |
+------------------+----------------------------------------+
| utf8mb4 | utf8 |
+------------------+----------------------------------------+
1 row in set, 1 warning (0.00 sec)
6.聚合函数
聚合(或聚集、分组)函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。
聚合函数作用于一组数据,并对一组数据返回一个值。
1.常用聚合函数
-
AVG()—>只适用于数值类型的字段(AVG = SUM / COUNT)
-
SUM()–>只适用于数值类型的字段
-
MAX()---->字符类型是排序
-
MIN()---->字符类型是排序
-
COUNT()------>效率count(*)最高
SELECT AVG(salary), MAX(salary),MIN(salary), SUM(salary) FROM employees SELECT MIN(hire_date), MAX(hire_date) FROM employees; SELECT COUNT(*) FROM employees WHERE department_id = 50;
2.group by的使用:根据此字句中的条件将表中数据分为若干组
#每个部门的平均工资,根据department_id分组
SELECT department_id,AVG(salary)
from employees
GROUP BY department_id;
#每个部门的平均工资,根据department_id和job_id分组
SELECT department_id,job_id,AVG(salary)
from employees
GROUP BY department_id,job_id;#此处两者前后顺序不影响结果
#下面是错误的
SELECT department_id,job_id,AVG(salary)
from employees
GROUP BY department_id;#没有根据job_id分组,则不可明确的显示是哪个job_id,可以运行,但是错误
结论:
1.ELECT 中出现的非组函数字段必须声明在group by 中,
反之,group by 声明的字段可以不出现在SELECT中。
2.group by 声明在from后,shere后,order by 前,limit前
3.mysql中group by 可以使用 with rollup,但是此时,慎重使用order by(互斥)
#使用 WITH ROLLUP 关键字之后,在所有查询出的分组记录之后增加一条记录,该记录计算#查询出的所有记录的总和,即统计记录数量。
SELECT department_id,AVG(salary)
FROM employees
WHERE department_id > 80
GROUP BY department_id WITH ROLLUP;
3.having的使用----->用来过滤数据的
开发中,使用having的前提是使用了group by(不用无意义)
having的意义就是替换在出现group by中的wh ere
练习:查询各个部门最高工资比1W高的部门
错误写法:当where中出现聚合函数时,需要使用having
SELECT department_id,MAX(salary)
FROM employees
WHERE MAX(salary)>10000
GROUP BY department_id;
#正确写法:having需要写在group by后
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)>10000;
#另一种正确写法:但是效率相较于having,低很多
SELECT department_id,MAX(salary)
FROM employees
WHERE salary>10000
GROUP BY department_id;
练习:查询id为10,20,30,40,50,60中部门最高工资比10000高的部门信息
方式一的执行效率高于方式二
#方式一
SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40,50,60)
GROUP BY department_id
HAVING MAX(salary)>10000;
#方式二
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING department_id IN (10,20,30,40,50,60) AND MAX(salary)>10000;
结论:
当过滤条件中右聚合函数时,则此过滤条件必须声明在HAVING中
当过滤条件中没有聚合函数时,则此过滤条件声明在HAVING和WHERE中都可以,但是建议声明在WHERE中
WHERE 和 HAVING的对比
- WHERE可以直接使用表中的字段为筛选条件,但是不可以使用分组中的计算函数作为筛选条件;having必须与group by 配合使用,可以把分组计算的函数和分组字段作为筛选条件
- 如果需要通过连接从关联表中获取需要的数据,where是先筛选后连接,而having是先连接后筛选
- 适用范围来说,having使用范围更广
- 如果没有过滤函数中,where中执行的效率比having更高
4.SQL底层执行原理
-
sql语句的完整结构
#SQL92 SELECT ...,...,.. FROM ...,..,.., WHERE 多表连接条件 AND 不包含聚合函数的过滤条件 GROUP BY ...,... HAVING 包含聚合函数的过滤条件 ORDER BY ...,..,(ASC,DESC) LIMIT ...,... #sql99 SELECT ...,...,..(存在聚合函数) FROM ...(LEFT,RIGHT)JOIN ... ON 多表连接条件 (LEFT,RIGHT)JOIN ... ON... WHERE 不包含聚合函数的过滤条件 GROUP BY ...,... HAVING 包含聚合函数的过滤条件 ORDER BY ...,..,(ASC,DESC) LIMIT ...,...
-
SQL语句的执行过程
FROM----->ON----->(LEFT/RIGHT JOIN)----->WHERE------>GROUP BY ------> HAVING ----->SELECT---->DISTINCT------>ORDER BY ----->LIMIT
7.子查询:
子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQL 4.1开始引入
SQL 中子查询的使用大大增强了 SELECT 查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出一个数据结果,然后与这个数据结果(可能是某个标量,也可能是某个集合)进行比较
1.子查询基本使用
SELECT select_list
FROM table
WHERE expr opterator(
SELECT select_list
FROM table
WHERE expr
);
练习:谁的工资比Abel高
SELECT last_name,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);
-
子查询(内查询)在主查询之前一次执行完成。
-
子查询的结果被主查询(外查询)使用 。
-
注意事项:
- 子查询要包含在括号内
- 将子查询放在比较条件的右侧
- 单行操作符对应单行子查询,多行操作符对应多行子查询
2. 子查询的分类
分类方式1:
我们按内查询的结果返回一条还是多条记录,将子查询分为 单行子查询 、 多行子查询 。
分类方式2:
我们按内查询是否被执行多次,将子查询划分为 相关(或关联)子查询 和 不相关(或非关联)子查询 。
子查询从数据表中查询了数据结果,如果这个数据结果只执行一次,然后这个数据结果作为主查询的条件进行执行,那么这样的子查询叫做不相关子查询。
同样,如果子查询需要执行多次,即采用循环的方式,先从外部查询开始,每次都传入子查询进行查询,然后再将结果反馈给外部,这种嵌套的执行方式就称为相关子查询
比如:
相关子查询:查询工资大于本部门平均工资的员工信息
不相关子查询:查询工资大于本公司平均工资的员工信息
3.子查询具体方式
编写技巧:
1.从外往里写:
2.从里往外写:
练习:查询工资比149号员工工资高的员工信息
SELECT salary
FROM employees
WHERE salary>(
SELECT salary
FROM employees
WHERE employee_id=149
);
练习:返回公司工资最少的员工的last_name,job_id和salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
SELECT MIN(salary)
FROM employees
);
题目:查询与141号或174号员工的manager_id和department_id相同的其他员工的employee_id,
manager_id,department_id
#方式一:
SELECT employee_id,manager_id,department_id
FROM employees
WHERE manager_id IN (
SELECT manager_id
FROM employees
WHERE employee_id IN (141,174)
) AND department_id in (
SELECT department_id
FROM employees
WHERE employee_id IN (141,174)
) AND employee_id not in (141,174);
#方式二
SELECT employee_id, manager_id, department_id
FROM employees
WHERE (manager_id, department_id) IN
(SELECT manager_id, department_id
FROM employees
WHERE employee_id IN (141,174))
AND employee_id NOT IN (141,174);
题目:查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT department_id,salary
FROM employees
WHERE department_id is not null
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id=50
)
子查询中的CASE问题
题目:显示员工的employee_id和last_name,和location,齐总若员工的department_id与location-id为1800的department_id相同,则location 为Canada,否则为USA
SELECT employee_id,last_name,(CASE department_id
WHEN ( SELECT department_id
FROM departments
where location_id = 1800)
THEN 'Canada'
ELSE 'USA' end) location
from employees e
子查询中的空值问题
子查询不返回任何行
SELECT last_name, job_id
FROM employees
WHERE job_id =
(SELECT job_id
FROM employees
WHERE last_name = 'Haas');
非法使用子查询(比如返回值不不止一个,不可以用等于号)
SELECT employee_id, last_name
FROM employees
WHERE salary =
(SELECT MIN(salary)
FROM employees
GROUP BY department_id);
4.多行子查询
1.返回结果是多行
-
IN 等于列表中的任意一个
# 查询薪水最低的人的id和名字 SELECT employee_id,last_name FROM employees WHERE salary IN ( SELECT MIN(salary) FROM employees GROUP BY department_id );
-
ANY 需要和单行比较操作符一起使用,和子查询返回的某一个值比较
#练习:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、姓名、job_id 以及salary #方法一:老方法 SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary<( SELECT MAX(salary) FROM employees WHERE job_id='IT_PROG' ) AND job_id!='IT_PROG'; #方式二:用ANY SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary< ANY ( SELECT salary FROM employees WHERE job_id='IT_PROG' ) AND job_id!='IT_PROG';
-
ALL 需要和单行比较操作符一起使用,和子查询返回的所有值比较
#返回其它job_id中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id以及salary #方式一:老方法 SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary<( SELECT MIN(salary) FROM employees WHERE job_id='IT_PROG' ) AND job_id!='IT_PROG'; #方式二:ALL FROM employees WHERE salary< ALL ( SELECT salary FROM employees WHERE job_id='IT_PROG' ) AND job_id!='IT_PROG';
-
SOME 实际上是ANY的别名,作用相同,一般常使用ANY
2.嵌套查询(较难)
#查询平均工资最低的部门id
#方式1:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(avg_sal)
FROM (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
) dept_avg_sal #把结果当做一个新表来查询
)
#方式2:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL (
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
)
3.空值问题
#错误写法
SELECT last_name
FROM employees
WHERE employee_id NOT IN (
SELECT manager_id
FROM employees
);
#正确写法
SELECT last_name
FROM employees
WHERE employee_id NOT IN (
SELECT manager_id
FROM employees
WHERE manager_id is not null
)
4.相关子查询
如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为 关联子查询 。
#题目:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
#方式一:相关子查询
SELECT last_name,salary,department_id
from employees e1
where salary > (
SELECT AVG(salary)
from employees e2
where department_id = e1.department_id
);
#方式二:在 FROM 中使用子查询
SELECT e1.last_name,e1.salary,e1.department_id
from employees e1,(
select department_id,avg(salary) as avg_sal
from employees
GROUP BY department_id
) as e2
where e1.department_id = e2.department_id
and e1.salary > e2.avg_sal
#查询员工的id,salary,按照department_name排序
select employee_id,salary
from employees e
order by (
select department_name
from departments d
where e.department_id= d.department_id
)
#若employees表中employee_id与job_history表中employee_id相同的数目不小于2,输出这些相同id的员工的employee_id,last_name和其job_id
select employee_id,last_name,job_id
from employees e
where 2<=(
select count(*)
from job_history j
where e.employee_id=j.employee_id
);
5.EXISTS与NOT EXISTS关键字
关联子查询通常与EXISTS操作符一起是使用,用来检查查询中是否存在满足条件的行
如果在子查询中没有满足条件的行
- 返回FALSE
- 继续在子查询中查询
如果如果在子查询中有满足条件的行
- 不在子查询中继续查找
- 条件返回TRUE
NOT EXISTS关键字表示不存在某种条件,则返回TRUE,否则返回FALSE
exists练习
#查询公司管理者的employee_id,last_name,job_id,department_id信息
#自连接
select distinct mgr.employee_id,mgr.last_name,mgr.job_id,mgr.department_id
from employees e join employees mgr
on e.manager_id=mgr.employee_id
#子查询
SELECT employee_id,last_name,job_id,department_id
from employees
where employee_id in (
select distinct manager_id
from employees
);
#使用exists
SELECT employee_id,last_name,job_id,department_id
from employees e1
where EXISTS(
SELECT *
from employees e2
where e1.employee_id= e2.manager_id
);
not exists练习
#查询departments表中,不存在于employees表中的部门的department_id和department_name
#not exists
select department_id,department_name
from departments d
where not EXISTS(
select *
from employees e
where e.department_id = d.department_id
);
#右外连接
select d.department_id,d.department_name
from employees e RIGHT join departments d on
e.department_id=d.department_id
where e.department_id is null
#子查询练习题
#1.查询和Zlotkey相同部门的员工姓名和工资
select e1.last_name,e1.salary
from employees e1
where department_id = (
select department_id
from employees e2
where e2.last_name='Zlotkey'
);
#2.查询工资比公司平均工资高的员工的员工号,姓名和工资。
select employee_id,last_name,salary
from employees
where salary >= (
select avg(salary)
FROM employees
);
#3.选择工资大于所有JOB_ID = 'SA_MAN'的员工的工资的员工的last_name, job_id, salary
select last_name,job_id,salary
from employees
where salary >= ALL(
select salary
from employees
where job_id='SA_MAN'
);
#4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
select employee_id,last_name
from employees
WHERE job_id in (
select job_id
from employees
where last_name like '%u%'
);
#5.查询在部门的location_id为1700的部门工作的员工的员工号
select employee_id,last_name
from employees e,departments d
where e.department_id=d.department_id
and d.location_id=1700
#6.查询管理者是King的员工姓名和工资
select last_name,salary
from employees
where manager_id = (
select manager_id
from employees
where last_name='King'
and manager_id is not null
) and last_name <>'King';
#7.查询工资最低的员工信息: last_name, salary
SELECT last_name,salary
from employees
where salary <= All(
SELECT salary
from employees
);
#8.查询平均工资最低的部门信息
select department_id
from employees
GROUP BY department_id
having avg(salary) <= (
select min(avg_sal)
from (select avg(salary) as avg_sal
from employees
GROUP BY department_id) as _t)
#9.查询平均工资最低的部门信息和该部门的平均工资(相关子查询)
select department_id,avg(salary)
from employees
GROUP BY department_id
having avg(salary) <= (
select min(avg_sal)
from (select avg(salary) as avg_sal
from employees
GROUP BY department_id) as _t)
#10.查询平均工资最高的 job 信息
select department_id,avg(salary),job_id
from employees
GROUP BY job_id
having avg(salary) >= (
select MAX(avg_sal)
from (
select avg(salary) as avg_sal
from employees
GROUP BY job_id
) as _t
)
#11.查询平均工资高于公司平均工资的部门有哪些?
select department_id,avg(salary)
from employees
GROUP BY department_id
having avg(salary) >= (
select avg(salary)
from employees
)
#12.查询出公司中所有 manager 的详细信息
select DISTINCT manager_id
from employees
where manager_id is not null
#13.各个部门中 最高工资中最低的那个部门的 最低工资是多少?
select Max(salary) as max,min(salary) as min
from employees
GROUP BY department_id
#14.查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary
----------------------------------------
SELECT last_name, department_id, email, salary
from employees
where manager_id =
select manager_id,AVG(salary)
from employees
GROUP BY department_id
having avg(salary) >= all(
select avg(salary)
from employees
GROUP BY department_id
) and manager_id<>90 ;
#15. 查询部门的部门号,其中不包括job_id是"ST_CLERK"的部门号
select distinct department_id
FROM employees
WHERE job_id <>'ST_CLERK' and department_id is not null
#16. 选择所有没有管理者的员工的last_name
SELECT last_name
from employees
where manager_id is null
#17.查询员工号、姓名、雇用时间、工资,其中员工的管理者为 'De Haan'
select employee_id,last_name,hire_date,salary
from employees
where manager_id = (
select manager_id
from employees
where last_name='De Haan'
);
#18.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资(相关子查询)
SELECT employee_id,department_id,last_name,salary
from employees e
GROUP BY department_id
having e.salary > all(
SELECT avg(salary)
from employees d
GROUP BY department_id
having e.department_id=d.department_id
);
#19.查询每个部门下的部门人数大于 5 的部门名称(相关子查询)
SELECT department_name
from departments d
GROUP BY department_id
having 5 < (
select count(*)
from employees e
GROUP BY department_id
having e.department_id=d.department_id
);
#20.查询每个国家下的部门个数大于 2 的国家编号(相关子查询)
select country_id
from countries
where 2 < region_id
s not null
#13.各个部门中 最高工资中最低的那个部门的 最低工资是多少?
select Max(salary) as max,min(salary) as min
from employees
GROUP BY department_id
#14.查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary
SELECT last_name, department_id, email, salary
from employees
where manager_id =
select manager_id,AVG(salary)
from employees
GROUP BY department_id
having avg(salary) >= all(
select avg(salary)
from employees
GROUP BY department_id
) and manager_id<>90 ;
#15. 查询部门的部门号,其中不包括job_id是"ST_CLERK"的部门号
select distinct department_id
FROM employees
WHERE job_id <>‘ST_CLERK’ and department_id is not null
#16. 选择所有没有管理者的员工的last_name
SELECT last_name
from employees
where manager_id is null
#17.查询员工号、姓名、雇用时间、工资,其中员工的管理者为 ‘De Haan’
select employee_id,last_name,hire_date,salary
from employees
where manager_id = (
select manager_id
from employees
where last_name=‘De Haan’
);
#18.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资(相关子查询)
SELECT employee_id,department_id,last_name,salary
from employees e
GROUP BY department_id
having e.salary > all(
SELECT avg(salary)
from employees d
GROUP BY department_id
having e.department_id=d.department_id
);
#19.查询每个部门下的部门人数大于 5 的部门名称(相关子查询)
SELECT department_name
from departments d
GROUP BY department_id
having 5 < (
select count(*)
from employees e
GROUP BY department_id
having e.department_id=d.department_id
);
#20.查询每个国家下的部门个数大于 2 的国家编号(相关子查询)
select country_id
from countries
where 2 < region_id