赞
踩
SQL:Structured Query Language结构化查询语言,它是使用关系模型的数据库应用语言,由IBM上世纪70年代开发出来。后由美国国家标准局(ANSI)开始着手制定SQL标准,先后有SQL-86,SQL-89,SQL-92,SQL-99等标准。
说明:一个语句可以分开多行编写,以;或\g结束
DDL(Data Definition Languages):数据定义语言,这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象。
CREATE
、DROP
、ALTER
等。DML(Data Manipulation Language):数据操作语言,用于添加、删除、更新和查询数据库记录,并检查数据完整性。
INSERT
、DELETE
、UPDATE
、SELECT
等。DCL(Data Control Language):数据控制语言,用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。
GRANT
、REVOKE
、COMMIT
、ROLLBACK
、SAVEPOINT
等。SELECT 标识选择哪些列
FROM 标识从哪个表中选择
SELECT *
FROM departments;
SELECT department_id, location_id
FROM departments;
重命名一个列
便于计算
紧跟列名,也可以在列名和别名之间加入关键字AS,别名使用双引号,以便在别名中包含空格或特殊的字符并区分大小写。
使用别名
SELECT last_name AS name, commission_pct comm
FROM employees;
SELECT last_name "Name", salary*12 "Annual Salary"
FROM employees;
默认情况下,查询会返回全部行,包括重复行。
SELECT department_id
FROM employees;
在SELECT语句中使用关键字DISTINCT去除重复行。
SELECT DISTINCT department_id
FROM employees;
SELECT employee_id,salary,commission_pct,
12 * salary * (1 + commission_pct) "annual_sal"
FROM employees;
使用DESCRIBE 或 DESC 命令,表示表结构。
DESCRIBE employees;
背景:
SELECT employee_id, last_name, job_id, department_id
FROM employees
WHERE department_id = 90 ;
操作符 | 含义 |
---|---|
= | 等于(不是==) |
> | 大于 |
>= | 大于、等于 |
< | 小于 |
<= | 小于、等于 |
<> 或 != | 不等于 |
说明:赋值符号使用 :=
SELECT last_name, salary
FROM employees
WHERE salary <= 3000;
操作符 | 含义 |
---|---|
BETWEEN … AND | 在两个值之间(包含边界) |
IN(set) | 等于值列表中的一个 |
LIKE | 模糊查询 |
IS NULL | 空值 |
1)BETWEEN … AND
使用 BETWEEN 运算来显示在一个区间内的值
SELECT last_name, salary
FROM employees
WHERE salary BETWEEN 2500 AND 3500;
2)IN
使用 IN运算显示列表中的值。
SELECT employee_id, last_name, salary, manager_id
FROM employees
WHERE manager_id IN (100, 101, 201);
3)LIKE
使用 LIKE 运算选择类似的值
选择条件可以包含字符或数字:
SELECT first_name
FROM employees
WHERE first_name LIKE 'S%';
SELECT last_name
FROM employees
WHERE last_name LIKE '_o%';
ESCAPE
SELECT job_id
FROM jobs
WHERE job_id LIKE ‘IT\_%‘;
如果使用\表示转义,要省略ESCAPE。如果不是\,则要加上ESCAPE。
SELECT job_id
FROM jobs
WHERE job_id LIKE ‘IT$_%‘ escape ‘$‘;
4)NULL
使用 IS (NOT) NULL 判断空值。
SELECT last_name, manager_id
FROM employees
WHERE manager_id IS NULL;
操作符 | 含义 |
---|---|
&& (或AND) | 逻辑且 |
||(或OR) | 逻辑或 |
NOT | 逻辑否 |
XOR | 逻辑异或 |
1)&& (或AND)
AND要求并的关系为真。
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary >=10000
AND job_id LIKE '%MAN%';
2)||(或OR)
OR要求或关系为真。
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary >= 10000
OR job_id LIKE '%MAN%';
3)NOT
SELECT last_name, job_id
FROM employees
WHERE job_id NOT IN ('IT_PROG', 'ST_CLERK', 'SA_REP');
4)XOR
select last_name,department_id,salary
from employees
where department_id in (10,20) XOR salary > 8000;
运算符 | 说明 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ (或div) | 除法 |
%(或mod) | 取模 |
SELECT employee_id,salary,department_id
FROM employees
WHERE department_id MOD 2 = 0;
使用 ORDER BY 子句排序
ORDER BY 子句在SELECT语句的结尾。
SELECT last_name, job_id, department_id, hire_date
FROM employees
ORDER BY hire_date ;
SELECT last_name, job_id, department_id, hire_date
FROM employees
ORDER BY hire_date DESC ;
SELECT employee_id, last_name, salary*12 annsal
FROM employees
ORDER BY annsal;
SELECT last_name, department_id, salary
FROM employees
ORDER BY department_id, salary DESC;
MySQL中使用limit实现分页
背景:查询返回的记录太多了,查看起来很不方便,怎么样能够实现分页查询呢?
分页原理
所谓分页显示,就是将数据库中的结果集,一段一段显示出来需要的条件。
--前10条记录:
SELECT * FROM table LIMIT 0,10;
--第11至20条记录:
SELECT * FROM table LIMIT 10,10;
--第21至30条记录:
SELECT * FROM table LIMIT 20,10;
SELECT * FROM table
LIMIT(PageNo - 1)*PageSize,PageSize;
举例:
从多个表中获取数据:
select last_name, department_name
from employees, departments;
演示笛卡尔积的错误情况:
select count(employee_id) from employees;
输出107行
select count(department_id)from departments;
输出27行
select 107*27 from dual;
笛卡尔积会在下面条件下产生:
为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。
MySQL连接
使用连接在多个表中查询数据。
SELECT table1.column, table2.column
FROM table1, table2
WHERE table1.column1 = table2.column2;
在 WHERE子句中写入连接条件。
在表中有相同列时,在列名之前加上表名前缀。
SELECT employees.employee_id, employees.last_name,
employees.department_id, departments.department_id,
departments.location_id
FROM employees, departments
WHERE employees.department_id = departments.department_id;
多个连接条件与 AND 操作符
区分重复的列名
使用表名前缀在多个表中区分相同的列。
在不同表中具有相同列名的列可以用表的别名加以区分。
表的别名
使用别名可以简化查询。
使用表名前缀可以提高执行效率。
SELECT e.employee_id, e.last_name, e.department_id,
d.department_id, d.location_id
FROM employees e , departments d
WHERE e.department_id = d.department_id;
连接多个表
连接 n个表,至少需要n-1个连接条件。
例如:连接三个表,至少需要两个连接条件。
练习:查询出公司员工的 last_name,department_name, city
SELECT e.last_name, e.salary, j.grade_level
FROM employees e, job_grades j
WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;
题目:查询employees表,返回“Xxx works for Xxx”
SELECT CONCAT(worker.last_name ,' works for '
, manager.last_name)
FROM employees worker, employees manager
WHERE worker.manager_id = manager.employee_id ;
练习:查询出last_name为 ‘Chen’ 的员工的 manager 的信息
内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。
自然连接中是以具有相同名字的列为连接条件的。
可以使用 ON 子句指定额外的连接条件。
这个连接条件是与其它条件分开的。
ON 子句使语句具有更高的易读性。
SELECT e.employee_id, e.last_name, e.department_id,
d.department_id, d.location_id
FROM employees e JOIN departments d
ON (e.department_id = d.department_id);
SELECT employee_id, city, department_name
FROM employees e
JOIN departments d
ON d.department_id = e.department_id
JOIN locations l
ON d.location_id = l.location_id;
只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字段值相等
SELECT employee_id,department_name
FROM employees e JOIN departments d
USING (department_id);
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id) ;
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id) ;
补充:
UNION操作符
UNION 操作符返回两个查询的结果集的并集。
UNION ALL操作符
UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。
两种SQL函数
单行函数
操作数据对象
接受参数返回一个结果
只对一行进行变换
每行返回一个结果
可以嵌套
参数可以是一列或一个值
函数 | 用法 |
---|---|
CONCAT(S1,S2,…,Sn) | 连接S1,S2,…,Sn为一个字符串 |
CONCAT_WS(s, S1,S2,…,Sn) | 同CONCAT(s1,s2,…)函数,但是每个字符串之间要加上s |
CHAR_LENGTH(s) | 返回字符串s的字符数 |
LENGTH(s) | 返回字符串s的字节数,和字符集有关 |
INSERT(str, index , len, instr) | 将字符串str从第index位置开始,len个字符长的子串替换为字符串instr |
UPPER(s) 或 UCASE(s) | 将字符串s的所有字母转成大写字母 |
LOWER(s) 或LCASE(s) | 将字符串s的所有字母转成小写字母 |
LEFT(s,n) | 返回字符串s最左边的n个字符 |
RIGHT(s,n) | 返回字符串s最右边的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(【BOTH 】s1 FROM s) | 去掉字符串s开始与结尾的s1 |
TRIM(LEADING s1 FROM s) | 去掉字符串s开始处的s1 |
TRIM(TRAILING s1 FROM s) | 去掉字符串s结尾处的s1 |
REPEAT(str, n) | 返回str重复n次的结果 |
REPLACE(str, a, b) | 用字符串b替换字符串str中所有出现的字符串a |
STRCMP(s1,s2) | 比较字符串s1,s2 |
SUBSTRING(s,index,len) | 返回从字符串s的index位置其len个字符 |
函数 | 结果 |
---|---|
LOWER(‘SQL Course’) | sql course |
UPPER(‘SQL Course’) | SQL COURSE |
这类函数改变字符的大小写。
函数 | 结果 |
---|---|
CONCAT(‘Hello’,‘World’) | HelloWorld |
SUBSTR(‘HelloWorld’,1,5) | Hello |
LENGTH(‘HelloWorld’) | 10 |
INSTR(‘HelloWorld’,‘W’) | 6 |
LPAD(salary,10,’*’) | *****24000 |
RPAD(salary,10, ‘*’) | 24000***** |
TRIM(‘H’ FROM ‘HelloWorld’) | elloWorld |
REPLACE(‘abcd’,‘b’,‘m’) | amcd |
函数 | 用法 |
---|---|
ABS(x) | 返回x的绝对值 |
CEIL(x) | 返回大于x的最小整数值 |
FLOOR(x) | 返回小于x的最大整数值 |
MOD(x,y) | 返回x/y的模 |
RAND() | 返回0~1的随机值 |
ROUND(x,y) | 返回参数x的四舍五入的有y位的小数的值 |
TRUNCATE(x,y) | 返回数字x截断为y位小数的结果 |
SQRT(x) | 返回x的平方根 |
POW(x,y) | 返回x的y次方 |
ROUND(45.926, 2) --> 45.93
TRUNCATE(45.926) --> 45
MOD(1600, 300) --> 100
函数 | 用法 |
---|---|
CURDATE() 或 CURRENT_DATE() | 返回当前日期 |
CURTIME() 或 CURRENT_TIME() | 返回当前时间 |
NOW() / SYSDATE() / CURRENT_TIMESTAMP() / LOCALTIME() / LOCALTIMESTAMP() | 返回当前系统日期时间 |
YEAR(date) / MONTH(date) / DAY(date) / HOUR(time) / MINUTE(time) / SECOND(time) | 返回具体的时间值 |
WEEK(date) / WEEKOFYEAR(date) | 返回一年中的第几周 |
DAYOFWEEK(date) | 返回周几,注意:周日是1,周一是2,。。。周六是7 |
WEEKDAY(date) | 返回周几,注意,周1是0,周2是1,。。。周日是6 |
DAYNAME(date) | 返回星期:MONDAY,TUESDAY…SUNDAY |
MONTHNAME(date) | 返回月份:January,。。。。。 |
DATEDIFF(date1,date2) / TIMEDIFF(time1, time2) | 返回date1 - date2的日期间隔 / 返回time1 - time2的时间间隔 |
DATE_ADD(datetime, INTERVAL expr type) | 返回与给定日期时间相差INTERVAL时间段的日期时间 |
DATE_FORMAT(datetime ,fmt) | 按照字符串fmt格式化日期datetime值 |
STR_TO_DATE(str, fmt) | 按照字符串fmt对str进行解析,解析为一个日期 |
其中:
(1)DATE_ADD(datetime,INTERVAL expr type)
表达式类型:
参数类型 | 参数类型 |
---|---|
YEAR | YEAR_MONTH |
MONTH | DAY_HOUR |
DAY | DAY_MINUTE |
HOUR | DAY_SECOND |
MINUTE | HOUR_MINUTE |
SECOND | HOUR_SECOND |
MINUTE_SECOND |
举例:
SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR);
SELECT DATE_ADD(NOW(), INTERVAL -1 YEAR); #可以是负数
SELECT DATE_ADD(NOW(), INTERVAL '1_1' YEAR_MONTH); #需要单引号
(2)DATE_FORMAT(datetime,fmt) 和 STR_TO_DATE(str, fmt)
格式符 | 说明 | 格式符 | 说明 |
---|---|---|---|
%Y | 4位数字表示年份 | %y | 表示两位数字表示年份 |
%M | 月名表示月份(January,…) | %m | 两位数字表示月份(01,02,03。。。) |
%b | 缩写的月名(Jan.,Feb.,…) | %c | 数字表示月份(1,2,3,…) |
%D | 英文后缀表示月中的天数(1st,2nd,3rd,…) | %d | 两位数字表示月中的天数(01,02…) |
%e | 数字形式表示月中的天数(1,2,3,4,5…) | ||
%H | 两位数字表示小数,24小时制(01,02…) | %h和%I | 两位数字表示小时,12小时制(01,02…) |
%k | 数字形式的小时,24小时制(1,2,3) | %l | 数字形式表示小时,12小时制(1,2,3,4…) |
%i | 两位数字表示分钟(00,01,02) | %S和%s | 两位数字表示秒(00,01,02…) |
%W | 一周中的星期名称(Sunday…) | %a | 一周中的星期缩写(Sun.,Mon.,Tues.,…) |
%w | 以数字表示周中的天数(0=Sunday,1=Monday…) | ||
%j | 以3位数字表示年中的天数(001,002…) | %U | 以数字表示年中的第几周,(1,2,3。。)其中Sunday为周中第一天 |
%u | 以数字表示年中的第几周,(1,2,3。。)其中Monday为周中第一天 | ||
%T | 24小时制 | %r | 12小时制 |
%p | AM或PM | %% | 表示% |
举例:
SELECT STR_TO_DATE('09/01/2009','%m/%d/%Y')
FROM DUAL;
SELECT STR_TO_DATE('20140422154706','%Y%m%d%H%i%s')
FROM DUAL;
SELECT STR_TO_DATE('2014-04-22 15:47:06','%Y-%m-%d %H:%i:%s')
FROM DUAL;
函数 | 用法 |
---|---|
IF(value,t ,f) | 如果value是真,返回t,否则返回f |
IFNULL(value1, value2) | 如果value1不为空,返回value1,否则返回value2 |
CASE WHEN 条件1 THEN result1 WHEN 条件2 THEN result2 … [ELSE resultn] END | 相当于Java的if…else if…else… |
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 … [ELSE 值n] END | 相当于Java的switch…case… |
SELECT employee_id,salary, CASE WHEN salary>=15000 THEN '高薪'
WHEN salary>=10000 THEN '潜力股'
WHEN salary>=8000 THEN '屌丝'
ELSE '草根' END "描述"
FROM employees;
SELECT oid,`status`, CASE `status` WHEN 1 THEN '未付款'
WHEN 2 THEN '已付款'
WHEN 3 THEN '已发货'
WHEN 4 THEN '确认收货'
ELSE '无效订单' END
FROM t_order;
SELECT employee_id,12 * salary * (1 + IFNULL(commission_pct,0))
FROM employees;
SELECT last_name, job_id, salary,
CASE job_id WHEN 'IT_PROG' THEN 1.10*salary
WHEN 'ST_CLERK' THEN 1.15*salary
WHEN 'SA_REP' THEN 1.20*salary
ELSE salary END "REVISED_SALARY"
FROM employees;
练习:查询部门号为 10,20, 30 的员工信息, 若部门号为 10, 则打印其工资的 1.1 倍, 20 号部门, 则打印其工资的 1.2 倍, 30 号部门打印其工资的 1.3 倍数。
函数 | 用法 |
---|---|
database() | 返回当前数据库名 |
version() | 返回当前数据库版本 |
user() | 返回当前登录用户名 |
password(str) | 返回字符串str的加密版本,41位长的字符串 |
md5(str) | 返回字符串str的md5值,也是一种加密方式 |
分组函数作用于一组数据,并对一组数据返回一个值。
组函数类型
组函数语法
可以对数值型数据使用AVG 和 SUM 函数。
SELECT AVG(salary), MAX(salary),MIN(salary), SUM(salary)
FROM employees
WHERE job_id LIKE '%REP%';
可以对任意数据类型的数据使用 MIN 和 MAX 函数。
SELECT MIN(hire_date), MAX(hire_date)
FROM employees;
COUNT(*)返回表中记录总数,适用于任意数据类型。
SELECT COUNT(*)
FROM employees
WHERE department_id = 50;
•COUNT(expr) 返回expr不为空的记录总数。
SELECT COUNT(commission_pct)
FROM employees
WHERE department_id = 50;
问题:用count(*),count(1)谁好呢?
其实,对于myisam引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。
Innodb引擎的表用count(*)直接读行数,效率很低,因为innodb真的要去数一遍。
可以使用GROUP BY子句将表中的数据分成若干组
SELECT column, group_function(column)
FROM table
[WHERE condition]
[GROUP BY group_by_expression]
[ORDER BY column];
明确:WHERE一定放在FROM后面
在SELECT列表中所有未包含在组函数中的列都应该包含在 GROUP BY子句中
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id ;
包含在 GROUP BY 子句中的列不必包含在SELECT 列表中
SELECT AVG(salary)
FROM employees
GROUP BY department_id ;
使用多个列分组
SELECT department_id dept_id, job_id, SUM(salary)
FROM employees
GROUP BY department_id, job_id ;
SELECT department_id, AVG(salary)
FROM employees
WHERE AVG(salary) > 8000
GROUP BY department_id;
过滤分组:HAVING子句
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)>10000 ;
SELECT ...,....,... FROM ...,...,.... WHERE 多表的连接条件 AND 不包含组函数的过滤条件 GROUP BY ...,... HAVING 包含组函数的过滤条件 ORDER BY ... ASC/DESC LIMIT ...,... 或 SELECT ...,....,... FROM ... JOIN ... ON 多表的连接条件 JOIN ... ON ... WHERE 不包含组函数的过滤条件 AND/OR 不包含组函数的过滤条件 GROUP BY ...,... HAVING 包含组函数的过滤条件 ORDER BY ... ASC/DESC LIMIT ...,...
执行的顺序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bm3POhD9-1600441310195)(C:\Users\ruiyu\AppData\Roaming\Typora\typora-user-images\1587744283625.png)]
实际问题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y7cHMYXB-1600441310196)(SQL开发.assets/1554991054388.png)]
子查询 (内查询) 在主查询之前一次执行完成。
子查询的结果被主查询(外查询)使用 。
子查询的类型:
单行子查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Prjvhcbg-1600441310196)(SQL开发.assets/1554991538719.png)]
多行子查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZWv7PRg0-1600441310197)(SQL开发.assets/1554991555669.png)]
注意事项
操作符 | 含义 |
---|---|
= | equal to |
> | greater than |
>= | greater than or equal to |
< | less than |
<= | less than or equal to |
<> | not equal to |
SELECT last_name
FROM employees
WHERE salary >
(SELECT salary
FROM employees
WHERE last_name = 'Abel');
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUeyaLQu-1600441310197)(SQL开发.assets/1554991316599.png)]
题目:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
SELECT last_name, job_id, salary
FROM employees
WHERE job_id =
(SELECT job_id
FROM employees
WHERE employee_id = 141)
AND salary >
(SELECT salary
FROM employees
WHERE employee_id = 143);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2aW7YwW-1600441310198)(SQL开发.assets/1554991892770.png)]
题目:返回公司工资最少的员工的last_name,job_id和salary
SELECT last_name, job_id, salary
FROM employees
WHERE salary =
(SELECT MIN(salary)
FROM employees);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pPmDMI0r-1600441310198)(SQL开发.assets/1554991935186.png)]
题目:查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary) >
(SELECT MIN(salary)
FROM employees
WHERE department_id = 50);
SELECT last_name, job_id
FROM employees
WHERE job_id =
(SELECT job_id
FROM employees
WHERE last_name = 'Haas');
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-brkwXY97-1600441310199)(SQL开发.assets/1554992067381.png)]
子查询不返回任何行
SELECT employee_id, last_name
FROM employees
WHERE salary =
(SELECT MIN(salary)
FROM employees
GROUP BY department_id);
多行子查询使用单行比较符
返回多行。
使用多行比较操作符。
操作符 | 含义 |
---|---|
IN | 等于列表中的任意一个 |
ANY | 和子查询返回的某一个值比较 |
ALL | 和子查询返回的所有值比较 |
体会any和all的区别
题目:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、姓名、job_id 以及salary
题目:返回其它job_id中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id以及salary
相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nlzzsI5-1600441310205)(C:/Users/ruiyu/AppData/Roaming/Typora/typora-user-images/1587744506653.png)]
说明:子查询中使用主查询中的列
题目:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
方式一:相关子查询
方式二:在from中使用子查询
SELECT last_name,salary,e1.department_id
FROM employees e1,(SELECT department_id,AVG(salary) dept_avg_sal FROM employees GROUP BY department_id) e2
WHERE e1.`department_id` = e2.department_id
AND e2.dept_avg_sal < e1.`salary`;
题目:查询员工的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`
);
EXISTS 操作符检查在子查询中是否存在满足条件的行
如果在子查询中存在满足条件的行:
如果在子查询中不存在满足条件的行:
题目:查询公司管理者的employee_id,last_name,job_id,department_id信息
方式一:
SELECT employee_id, last_name, job_id, department_id
FROM employees e1
WHERE EXISTS ( SELECT 'X'
FROM employees e2
WHERE e2.manager_id =
e1.employee_id);
方式二:
SELECT DISTINCT e1.employee_id, e1.last_name, e1.job_id, e1.department_id
FROM employees e1 JOIN employees e2
WHERE e1.employee_id = e2.manager_id;
方式三:
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE employee_id IN (
SELECT DISTINCT manager_id
FROM employees
);
题目:查询departments表中,不存在于employees表中的部门的department_id和department_name
SELECT department_id, department_name
FROM departments d
WHERE NOT EXISTS (SELECT 'X'
FROM employees
WHERE department_id = d.department_id);
UPDATE table1 alias1
SET column = (SELECT expression
FROM table2 alias2
WHERE alias1.column = alias2.column);
使用相关子查询依据一个表中的数据更新另一个表的数据。
练习:
1)
ALTER TABLE employees
ADD(department_name VARCHAR2(14));
2)
UPDATE employees e
SET department_name = (SELECT department_name
FROM departments d
WHERE e.department_id = d.department_id);
DELETE FROM table1 alias1
WHERE column operator (SELECT expression
FROM table2 alias2
WHERE alias1.column = alias2.column);
使用相关子查询依据一个表中的数据删除另一个表的数据
题目:删除表employees中,其与emp_history表皆有的数据
DELETE FROM employees e
WHERE employee_id in
(SELECT employee_id
FROM emp_history
WHERE employee_id = e.employee_id);
create database employees;
注意:database不能改名。一些可视化工具可以改名,它是建新库,把所有表复制到新库,再删旧库完成的。
show databases;
use 数据库名;
show tables from 数据库名;
drop database 数据库名;
SELECT DATABASE() from dual;
注意:要操作表格和数据之前必须先说明是对哪个数据库进行操作,否则就要对所有对象加上“数据库名.”。
数据类型 | 描述 |
---|---|
INT | 从-231到231-1的整型数据。存储大小为 4个字节 |
CHAR(size) | 定长字符数据。若未指定,默认为1个字符,最大长度255 |
VARCHAR(size) | 可变长字符数据,根据字符串实际长度保存,必须指定长度 |
FLOAT(M,D) | 单精度,M=整数位+小数位,D=小数位。 D<=M<=255,0<=D<=30,默认M+D<=6 |
DOUBLE(M,D) | 双精度。D<=M<=255,0<=D<=30,默认M+D<=15 |
DATE | 日期型数据,格式’YYYY-MM-DD’ |
BLOB | 二进制形式的长文本数据,最大可达4G |
TEXT | 长文本数据,最大可达4G |
CREATE TABLE [schema.]table
(column datatype [DEFAULT expr][, ...]);
CREATE TABLE dept(
deptno INT(2),
dname VARCHAR(14),
loc VARCHAR(13));
DESCRIBE dept;
--创建表
CREATE TABLE emp (
--int类型,自增
emp_id INT AUTO_INCREMENT,
--最多保存20个中英文字符
emp_name CHAR (20),
--总位数不超过15位
salary DOUBLE,
--日期类型
birthday DATE,
--主键
PRIMARY KEY (emp_id)
) ;
SHOW CREATE TABLE 表名;
使用 AS subquery 选项,将创建表和插入数据结合起来
指定的列和子查询中的列要一一对应
通过列名和默认值定义列
create table emp1 as select * from employees;
create table emp2 as select * from employees where 1=2; --创建的emp2是空表
CREATE TABLE dept80
AS
SELECT employee_id, last_name, salary*12 ANNSAL, hire_date
FROM employees
WHERE department_id = 80;
DESCRIBE dept80;
使用 ALTER TABLE 语句可以实现:
向已有的表中添加列
修改现有表中的列
删除现有表中的列
重命名现有表中的列
ALTER TABLE dept80
ADD job_id varchar(15);
ALTER TABLE dept80
MODIFY (last_name VARCHAR(30));
ALTER TABLE dept80
MODIFY (salary double(9,2) default 1000);
使用 CHANGE old_column new_column dataType子句重命名列。
ALTER TABLE dept80
CHANGE department_name dept_name varchar(15);
使用 DROP COLUMN 子句删除不再需要的列。
ALTER TABLE dept80
DROP COLUMN job_id;
执行RENAME语句改变表, 视图的名称
RENAME TABLE emp
TO myemp;
ALTER table dept
RENAME [TO] detail_dept; -- [TO]可以省略
必须是对象的拥有者
数据和结构都被删除
所有正在运行的相关事务被提交
所有相关索引被删除
DROP TABLE 语句不能回滚
DROP TABLE dept80;
TRUNCATE TABLE detail_dept;
TRUNCATE语句不能回滚
可以使用 DELETE 语句删除数据,可以回滚
对比:
set autocommit = false;
delete from emp2;
select * from emp2;
rollback;
select * from emp2;
**事务:一组逻辑操作单元,**使数据从一种状态变换到另一种状态。
数据库事务由以下的部分组成:
事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。
当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
具体过程:
COMMIT和ROLLBACK语句的优点
数据完整性:
存储在数据库中的所有数据值均处于正确的状态。如果数据库中存储有不正确的数据值,则该数据库称为已丧失数据完整性。
数据库采用多种方法来保证数据完整性,包括外键、束约、规则和触发器。
提交或回滚前的数据状态
提交后的数据状态
数据回滚后的状态
使用 ROLLBACK 语句可使数据变化失效:
数据改变被取消。
修改前的数据状态可以被恢复。
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。
**一个事务与其他事务隔离的程度称为隔离级别。**数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
数据库提供的 4 种事务隔离级别:
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。 Oracle 默认的事务隔离级别为: READ COMMITED 。
Mysql 支持 4 种事务隔离级别。 Mysql 默认的事务隔离级别为: REPEATABLE READ
在MySql中设置隔离级别
set tx_isolation ='repeatable-read';
set global tx_isolation ='read-committed';
注意:这里的隔离级别中间是减号,不是下划线。
INSERT INTO departments(department_id, department_name,
manager_id, location_id)
VALUES (70, 'Pub', 100, 1700);
向表中插入空值
INSERT INTO departments (department_id,department_name )
VALUES (30, 'Purchasing');
INSERT INTO departments
VALUES (100, 'Finance', NULL, NULL);
INSERT INTO emp(NAME)
VALUES('Tom'),('Jerry'),('Rose');
INSERT INTO emp2
SELECT *
FROM employees
WHERE department_id = 90;
INSERT INTO sales_reps(id, name, salary, commission_pct)
SELECT employee_id, last_name, salary, commission_pct
FROM employees
WHERE job_id LIKE '%REP%';
可以一次更新多条数据。
如果需要回滚数据,需要保证在DML前,进行设置:SET AUTOCOMMIT = FALSE;
UPDATE employees
SET department_id = 70
WHERE employee_id = 113;
UPDATE copy_emp
SET department_id = 110;
UPDATE employees
SET department_id = 55
WHERE department_id = 110;
说明:不存在 55 号部门
DELETE FROM departments
WHERE department_name = 'Finance';
DELETE FROM copy_emp;
DELETE FROM departments
WHERE department_id = 60;
说明:You cannot delete a row that contains a primary key that is used as a foreign key in another table.
注意: MySQL不支持check约束,但可以使用check约束,而没有任何效果
SELECT * FROM information_schema.table_constraints
WHERE table_name = 'employees';
非空约束用于确保当前列的值不为空值,非空约束只能出现在表对象的列上。
Null类型特征:
创建 not null 约束
CREATE TABLE emp(
id INT(10) NOT NULL,
NAME VARCHAR(20) NOT NULL DEFAULT 'abc',
sex CHAR NULL
);
ALTER TABLE emp
MODIFY sex VARCHAR(30) NOT NULL;
ALTER TABLE emp
MODIFY sex VARCHAR(30) NULL;
ALTER TABLE emp
MODIFY NAME VARCHAR(15) DEFAULT 'abc' NULL;
同一个表可以有多个唯一约束。
唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯一。
在创建唯一约束的时候,如果不给唯一约束名称,就默认和列名相同。
MySQL会给唯一约束的列上默认创建一个唯一索引。
CREATE TABLE t_course(
cid INT PRIMARY KEY,
cname VARCHAR(100) UNIQUE,
description VARCHAR(200)
);
CREATE TABLE USER(
id INT NOT NULL,
NAME VARCHAR(25),
PASSWORD VARCHAR(16),
--使用表级约束语法
CONSTRAINT uk_name_pwd UNIQUE(NAME,PASSWORD)
);
表示用户名和密码组合不能重复
ALTER TABLE USER
ADD UNIQUE(NAME,PASSWORD);
ALTER TABLE USER
ADD CONSTRAINT uk_name_pwd UNIQUE(NAME,PASSWORD);
ALTER TABLE USER
MODIFY NAME VARCHAR(20) UNIQUE;
删除约束
ALTER TABLE USER
DROP INDEX uk_name_pwd;
注意:如果忘记名称,可以通过“
show index from 表名称
;”查看。
主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值
如果是多列组合的主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
每个表最多只允许一个主键,建立主键约束可以在列级别创建,也可以在表级别上创建。
MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
当创建主键约束时,系统默认会在所在的列和列组合上建立对应的主键索引。删除主键时,也会直接删除主键索引。
CREATE TABLE emp4(
id INT PRIMARY KEY AUTO_INCREMENT ,
NAME VARCHAR(20)
);
CREATE TABLE emp5(
id INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20),
pwd VARCHAR(15),
CONSTRAINT emp5_id_pk PRIMARY KEY(id)
);
CREATE TABLE emp6(
id INT NOT NULL,
NAME VARCHAR(20),
pwd VARCHAR(15),
CONSTRAINT emp7_pk PRIMARY KEY(NAME,pwd)
);
删除主键约束
ALTER TABLE emp5
DROP PRIMARY KEY;
说明:删除主键约束,不需要指定主键名,因为一个表只有一个主键,删除主键约束后,非空还存在。
ALTER TABLE emp5
ADD PRIMARY KEY(NAME,pwd);
ALTER TABLE emp5
MODIFY id INT PRIMARY KEY;
基本理解:
注意点:
创建外键约束
CREATE TABLE dept(
dept_id INT AUTO_INCREMENT PRIMARY KEY,
dept_name VARCHAR(20)
);
CREATE TABLE emp(
emp_id INT AUTO_INCREMENT PRIMARY KEY,
last_name VARCHAR(15),
dept_id INT,
CONSTRAINT emp_dept_id_fk FOREIGN KEY(dept_id)
REFERENCES dept(dept_id)
);
– FOREIGN KEY: 在表级指定子表中的列
– REFERENCES: 标示在父表中的列
创建多列外键组合,必须使用表级约束
CREATE TABLE classes(
id INT,
NAME VARCHAR(20),
number INT,
PRIMARY KEY(NAME,number)
);
CREATE TABLE student(
id INT AUTO_INCREMENT PRIMARY KEY,
classes_name VARCHAR(20),
classes_number INT,
FOREIGN KEY(classes_name,classes_number)
REFERENCES classes(NAME,number)
);
删除外键约束
ALTER TABLE emp
DROP FOREIGN KEY emp_dept_id_fk;
说明:外键列上的索引,需要单独删除。比如:
ALTER TABLE 表名称 DROP INDEX 外键列索引名; ALTER TABLE t_emp DROP INDEX dept_id; -- 举例
- 1
- 2
查看索引名:
show index from 表名称;
- 1
ALTER TABLE emp
ADD [CONSTRAINT emp_dept_id_fk] FOREIGN KEY(dept_id)
REFERENCES dept(dept_id);
CREATE TABLE student(
id INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(20),
classes_name VARCHAR(20),
classes_number INT,
/*表级别联合外键*/
FOREIGN KEY(classes_name, classes_number)
REFERENCES classes(NAME, number) ON DELETE CASCADE);
CREATE TABLE student(
id INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(20),
classes_name VARCHAR(20),
classes_number INT,
/*表级别联合外键*/
FOREIGN KEY(classes_name, classes_number)
REFERENCES classes(NAME, number) ON UPDATE CASCADE);
CREATE TABLE temp(
id INT AUTO_INCREMENT,
NAME VARCHAR(20),
age INT CHECK(age > 20),
PRIMARY KEY(id)
);
CREATE TABLE myemp(
id INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(15),
salary DOUBLE(10,2) DEFAULT 2000
);
对象 | 描述 |
---|---|
表(TABLE) | 基本的数据存储集合,由行和列组成 |
视图(VIEW) | 从表中抽出的逻辑上相关的数据集合 |
序列(SEQUENCE) | 提供有规律的数值。 |
索引(INDEX) | 提高查询的效率 |
同义词(SYNONYM) | 给对象起别名 |
视图是一种虚表
视图建立在已有表的基础上, 视图赖以建立的这些表称为基表
向视图提供数据内容的语句为 SELECT 语句, 可以将视图理解为存储起来的 SELECT 语句
视图向用户提供基表数据的另一种表现形式
为什么使用视图?
简单视图和复杂视图
特性 | 简单视图 | 复杂视图 |
---|---|---|
表的数量 | 一个 | 一个或多个 |
函数 | 没有 | 有 |
分组 | 没有 | 有 |
DML操作 | 可以 | 有时可以 |
创建视图
CREATE VIEW empvu80
AS
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id = 80;
create or replace view empview
as
select employee_id emp_id,last_name name,department_name
from employees e,departments d
Where e.department_id = d.department_id;
创建视图时在子查询中给列定义别名
CREATE VIEW salvu50
AS
SELECT employee_id ID_NUMBER, last_name NAME,salary*12 ANN_SALARY
FROM employees
WHERE department_id = 50;
DESCRIBE empvu80;
说明:在选择视图中的列时应使用别名
SELECT *
FROM salvu80;
CREATE OR REPLACE VIEW empvu80
(id_number, name, sal, department_id)
AS
SELECT employee_id, first_name || ' ' || last_name, salary, department_id
FROM employees
WHERE department_id = 80;
说明:CREATE VIEW 子句中各列的别名应和子查询中各列相对应。
CREATE VIEW dept_sum_vu
(name, minsal, maxsal, avgsal)
AS
SELECT d.department_name, MIN(e.salary), MAX(e.salary),AVG(e.salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;
视图中使用DML的规定
可以在简单视图中使用DML操作
当视图定义中包含以下元素之一时不能使用delete:
当视图定义中包含以下元素之一时不能使用update:
当视图定义中包含以下元素之一时不能使用insert:
删除视图
删除视图只是删除视图的定义,并不会删除基表的数据。
DROP VIEW empvu80;
### 8.3 索引(INDEX) #### 8.3.1 基本介绍 - 一种独立于表的模式对象, 可以存储在与表不同的磁盘或表空间中,**是一个单独的、物理的数据库结构** - 索引被删除或损坏, 不会对表产生影响, 其影响的只是**查询的速度** - 索引一旦建立, 数据库管理系统会对其进行自动维护, 而且由数据库管理系统决定何时使用索引。用户不用在查询语句中指定使用哪个索引 - 在删除一个表时,所有基于该表的索引会自动被删除 - 通过指针加速数据库服务器的查询速度 - **通过快速定位数据的方法,减少磁盘** **I/O** #### 8.3.2 索引的介绍 例如:一本字典,如何快速找到某个字,可以给字典加目录,对数据库来说,索引的作用即是给"数据"加目录。 设有N条随机记录,不用索引,平均查找N/2次,那么用了索引之后呢。如果是btree(二叉树)索引, 则是logN。 如果是hash(哈希)索引,时间复杂度是1。 - MySQL提供多种索引类型供选择: - 普通索引 - 唯一性索引 - 主键索引:只有一个主键索引 - 全文索引:MySQL5.X版本只有MyISAM存储引擎支持FULLTEXT,并且只限于CHAR、VARCHAR和TEXT类型的列上创建。 - **MySQL的索引方法:** - HASH - BTREE(MySQL中多数索引都以BTREE的形式保存。) #### 8.3.3 创建索引 - **自动创建**: 在定义 PRIMARY KEY 或 UNIQUE 约束后系统自动在相应的列上创建**唯一性**索引 - **手动创建**: 用户可以在其它列上创建非唯一的索引,以加速查询 - 在一个或多个列上创建索引 ![image-20200717005009015](https://img-blog.csdnimg.cn/img_convert/61960bcbdcf3e7c996776dde2ddca5d1.png) - 在表 EMPLOYEES的列 LAST_NAME 上创建索引 ```sql CREATE INDEX emp_last_name_idx ON employees(last_name);
索引的优缺点
什么时候创建索引
以下情况可以创建索引:
列中数据值分布范围很广
列经常在 WHERE 子句或连接条件中出现
表经常被访问而且数据量很大 ,访问的数据大概占数据总量的2%到4%
什么时候不要创建索引
下列情况不要创建索引:
索引不需要用,只是说我们在用name进行查询的时候,速度会更快。当然查的速度快了,插入的速度就会慢。因为插入数据的同时,还需要维护一个索引。
DROP INDEX upper_last_name_idx
ON uppers;
改视图**
CREATE OR REPLACE VIEW empvu80
(id_number, name, sal, department_id)
AS
SELECT employee_id, first_name || ' ' || last_name, salary, department_id
FROM employees
WHERE department_id = 80;
说明:CREATE VIEW 子句中各列的别名应和子查询中各列相对应。
CREATE VIEW dept_sum_vu
(name, minsal, maxsal, avgsal)
AS
SELECT d.department_name, MIN(e.salary), MAX(e.salary),AVG(e.salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;
视图中使用DML的规定
可以在简单视图中使用DML操作
当视图定义中包含以下元素之一时不能使用delete:
当视图定义中包含以下元素之一时不能使用update:
当视图定义中包含以下元素之一时不能使用insert:
删除视图
删除视图只是删除视图的定义,并不会删除基表的数据。
DROP VIEW empvu80;
### 8.3 索引(INDEX) #### 8.3.1 基本介绍 - 一种独立于表的模式对象, 可以存储在与表不同的磁盘或表空间中,**是一个单独的、物理的数据库结构** - 索引被删除或损坏, 不会对表产生影响, 其影响的只是**查询的速度** - 索引一旦建立, 数据库管理系统会对其进行自动维护, 而且由数据库管理系统决定何时使用索引。用户不用在查询语句中指定使用哪个索引 - 在删除一个表时,所有基于该表的索引会自动被删除 - 通过指针加速数据库服务器的查询速度 - **通过快速定位数据的方法,减少磁盘** **I/O** #### 8.3.2 索引的介绍 例如:一本字典,如何快速找到某个字,可以给字典加目录,对数据库来说,索引的作用即是给"数据"加目录。 设有N条随机记录,不用索引,平均查找N/2次,那么用了索引之后呢。如果是btree(二叉树)索引, 则是logN。 如果是hash(哈希)索引,时间复杂度是1。 - MySQL提供多种索引类型供选择: - 普通索引 - 唯一性索引 - 主键索引:只有一个主键索引 - 全文索引:MySQL5.X版本只有MyISAM存储引擎支持FULLTEXT,并且只限于CHAR、VARCHAR和TEXT类型的列上创建。 - **MySQL的索引方法:** - HASH - BTREE(MySQL中多数索引都以BTREE的形式保存。) #### 8.3.3 创建索引 - **自动创建**: 在定义 PRIMARY KEY 或 UNIQUE 约束后系统自动在相应的列上创建**唯一性**索引 - **手动创建**: 用户可以在其它列上创建非唯一的索引,以加速查询 - 在一个或多个列上创建索引 [外链图片转存中...(img-oCIu6nO5-1600441310218)] - 在表 EMPLOYEES的列 LAST_NAME 上创建索引 ```sql CREATE INDEX emp_last_name_idx ON employees(last_name);
索引的优缺点
什么时候创建索引
以下情况可以创建索引:
列中数据值分布范围很广
列经常在 WHERE 子句或连接条件中出现
表经常被访问而且数据量很大 ,访问的数据大概占数据总量的2%到4%
什么时候不要创建索引
下列情况不要创建索引:
索引不需要用,只是说我们在用name进行查询的时候,速度会更快。当然查的速度快了,插入的速度就会慢。因为插入数据的同时,还需要维护一个索引。
[外链图片转存中…(img-4e3oRxis-1600441310219)]
DROP INDEX upper_last_name_idx
ON uppers;
只有索引的拥有者或拥有DROP ANY INDEX 权限的用户才可以删除索引
删除操作是不可回滚的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。