本文适合有一定基础的进行快速简单回顾复习。
对于现如今的无论哪一类软件或应用,都几乎无法离开数据库,常见使用的关系性数据库如MySQL、Oracle,非关系性数据库如MongoDB、Redis等。而MySQL数据库则是软件开发中最常用的数据库之一,熟练掌握SQL语言还是非常重要的,对于某些岗位来说可能并没有经常使用,虽然简单但是太久没用还是会有所遗忘,所以在此进行一定的回顾。本篇文章主要介绍MySQL,不过大部分语句在Oracle、SQL Server、PostgreSQL等数据库上同样适用。
首先对于SQL可以基本分为以下几种分类:
数据定义语言 (Data Definition Language, DDL) |
这些语句负责管理和定义数据库的基础数据,如数据库、表、索引和视图等。主要的语句关键字包括create、drop和alter等 |
数据操作语言 (Data Manipulation Language, DML) |
这些语句可以执行数据的插入、删除、更新和查询操作。主要的语句关键字有 insert、delete、update等 |
数据查询语言 (Data Query Language, DQL) |
即最常用的select语句 |
数据控制语言 (Data Control Language, DCL) |
这些语句用于控制对数据库中数据段的访问权限和安全级别。主要的语句关键字包括grant、revoke、commit和rollback等 |
便于回顾与使用,本文使用的数据库表是网上找的三张表departments、employees、job_history,分别定义了
执行语句如下
-- 删除表(防止有这几张表,没有可不要)
DROP TABLE job_history;
DROP TABLE employees;
DROP TABLE departments;
-- 创建部门表
CREATE TABLE departments (
deptno INT PRIMARY KEY,
dname VARCHAR ( 12 ) NOT NULL,
managerno INT,
loc VARCHAR ( 10 )
);
-- 向部门表中插入记录
INSERT INTO departments
VALUES
( 1, '开发部', 2, '一楼' );
INSERT INTO departments
VALUES
( 2, '测试部', 3, '二楼' );
INSERT INTO departments
VALUES
( 3, '销售部', 8, '一楼' );
INSERT INTO departments
VALUES
( 4, '新业务部', NULL, '二楼' );
-- 创建员工表
CREATE TABLE employees (
empno INT PRIMARY KEY,
NAME CHAR ( 10 ) NOT NULL,
deptno INT,
email VARCHAR ( 20 ),
hiredate date,
salary NUMERIC ( 8, 2 ) DEFAULT 8000.00,
FOREIGN KEY ( deptno ) REFERENCES departments ( deptno )
);
-- 向员工表中插入记录
INSERT INTO employees
VALUES
( 1, '周福生', NULL, '[email protected]', '2000-12-02', 90000.00 );
INSERT INTO employees
VALUES
( 2, '王五', 1, '[email protected]', '2013-01-03', 9100.00 );
INSERT INTO employees
VALUES
( 3, '李四', 2, '[email protected]', '2021-02-10', 13900.00 );
INSERT INTO employees
VALUES
( 4, '赵六', 1, '[email protected]', '2022-12-1', 15000.00 );
INSERT INTO employees
VALUES
( 5, '李明', 1, '[email protected]', '2004-09-11', 25200.00 );
INSERT INTO employees
VALUES
( 6, '孙军', 2, '[email protected]', '2016-05-22', 9700.00 );
INSERT INTO employees
VALUES
( 7, '钱杰', 3, '[email protected]', '2013-07-22', 8900.00 );
INSERT INTO employees
VALUES
( 8, '程娟', 3, '[email protected]', '2013-07-22', 14900.00 );
INSERT INTO employees
VALUES
( 9, '赵卫华', 1, '[email protected]', '2009-11-12', 21900.00 );
-- 创建岗位历史表
CREATE TABLE job_history (
empno INT,
start_date date,
end_date date,
deptno INT,
PRIMARY KEY ( empno, start_date ),
FOREIGN KEY ( empno ) REFERENCES employees ( empno )
);
-- 向岗位历史表中插入数据
INSERT INTO job_history
VALUES
( 2, '2013-01-03', '2015-12-31', 3 );
INSERT INTO job_history
VALUES
( 2, '2016-01-01', '2018-12-31', 2 );
INSERT INTO job_history
VALUES
( 3, '2015-01-01', '2017-12-31', 2 );
INSERT INTO job_history
VALUES
( 4, '2010-01-01', '2015-12-31', 1 );
INSERT INTO job_history
VALUES
( 5, '2015-06-30', '2016-12-31', 2 );
INSERT INTO job_history
VALUES
( 9, '2009-11-12', '2010-12-31', 1 );
COMMIT;
CREATE TABLE 表名 { 列名 数据类型 }
create table departments(
deptno int primary key,
dname varchar(12) not null,
managerno int,
loc varchar(10)
);
附常用数据类型
数据类型 | 描述 |
---|---|
char(size) | 保存固定长度的字符串,最大长度size |
varchar(size) | 保存可变长度的字符串,最大长度size,若值大于255则将被转换为TEXT类型 |
tinytext | 最大长度2^8-1的字符串 |
text | 最大长度2^16-1的字符串 |
mediumtext | 最大长度2^24-1字符的字符串 |
longtext | 最大长度2^32-1字符的字符串 |
tinyint | 整数型,有符号(-2^7,2^7),无符号(0,2^8) |
smallint | 整数型,有符号(-2^15,2^15),无符号(0,2^16) |
mediumint | 整数型,有符号(-2^23,2^23),无符号(0,2^24) |
int / interger | 整数型,有符号(-2^31,2^31),无符号(0,2^32) |
bigint | 整数型,有符号(-2^63,2^63),无符号(0,2^64) |
bool | 布尔类型,只有 true 和 false 两个有效值,零值被认为是 false,非零值被认为是 true。MySQL 并不真正支持 bool 类型,bool 是 TINYINT(1) 的别名。 |
float(size,d) | 单精度浮点数,最大长度为size,小数点后d位,超过d位会被四舍五入 |
double(size,d) | 双精度浮点数,最大长度为size,小数点后d位,超过d位会被四舍五入 |
decimal(size,d) | 定点数类型,最大长度为size,小数点后d位,超过d位会被四舍五 (MySQL 用 4 个字节存储 FLOAT 类型数据,用 8 个字节来存储 DOUBLE 类型数据。无论哪个,都是采用二进制的方式来进行存储的,如果尾数不是0或5就无法用二进制精准表达,需要使用定点数) |
date | 日期类型,格式为 YYYY-MM-DD,取值范围从 '1000-01-01' 到 '9999-12-31' |
time | 时间类型,格式为HH:MM:SS,取值范围从 '-838:59:59' 到 '838:59:59' |
datetime | 日期时间类型,格式为 YYYY-MM-DD HH:MM:SS,取值范围从 '1000-01-01 00:00:00' 到 '9999-12-31 23:59:59' |
SELECT 列名称 FROM 表名称
-- 查询全部字段,但是一般使用具体字段名,若有%和空格等特殊符号需要用""括起来
SELECT * FROM employees;
SELECT empno,name,salary FROM employees;
SELECT empno,name,salary,salary*12+1000 AS annual_salary FROM employees;
SELECT name 姓名,salary 薪水, salary*12 "年薪%" FROM employees;
从表里选择数据进行操作时,可以使用WHERE进行条件过滤,例如进行查询记录或更新记录等,语法为 SELECT 列名称 FROM 表名称 WHERE 条件
-- where后加上查询条件
SELECT name,salary,hiredate FROM employees WHERE hiredate < '2020/01/01';
SELECT name,salary,hiredate FROM employees WHERE deptno != 3;
对于一张表的某些列存在多个重复值时,可以使用DISTINCT进行去冲显示,只需要加在列名称之前,语法 SELECT DISTINCT 列名称 FROM 表名称
-- 使用DISTINCT关键字可以去重复值
SELECT DISTINCT deptno FROM employees;
SELECT DISTINCT empno FROM job_history;
若WHERE子句中有需要过滤多个条件,则可以使用AND或OR将条件进行连接。条件1和条件2都满足则使用AND,条件1或条件2满足其一即可则使用OR,很好理解。NOT就表示不,即相反。不等于的运算符可以是!=或<>,都可以。
-- OR AND NOT 的用法
SELECT * FROM employees WHERE deptno = 3;
SELECT * FROM employees WHERE deptno = 3 AND salary > 10000;
SELECT * FROM employees WHERE deptno = 3 OR salary > 10000;
-- AND的优先级大于OR
SELECT * FROM employees
WHERE deptno = 3 OR salary > 10000 AND hiredate > '2015-01-01';
SELECT * FROM employees
WHERE deptno = 3 OR (salary > 10000 AND hiredate > '2015-01-01');
-- NOT的用法
SELECT * FROM employees WHERE deptno = 3 OR salary > 10000;
SELECT * FROM employees WHERE NOT (deptno = 3 OR salary > 10000);
SELECT * FROM employees WHERE deptno != 3 AND salary < 10000;
INSERT INTO 表名称 VALUES (值1,值2,值3……)
INSERT INTO 表名称(列1,列2……) VALUES(值1,值2……)
-- 向部门表中插入记录 按表字段顺序
INSERT INTO departments VALUES ( 1, '开发部', 2, '一楼' );
INSERT INTO departments VALUES ( 2, '测试部', 3, '二楼' );
-- 也可以指定需要插入数据的列名
INSERt INTO departments(deptno,dname,loc) VALUES (3, '销售部', '三楼');
UPDATE顾名思义主要用来更新表的数据,即修改表数据。
UPDATE 表名称 SET 列名称 = 更改后的值 WHERE 列名称 = 某值
-- UPDATE更新单个数据
SELECT * FROM employees WHERE empno = 3;
UPDATE employees SET deptno = 3 WHERE empno = 3;
SELECT * FROM employees WHERE empno = 3;
-- UPDATE更新多个数据
SELECT * FROM employees WHERE empno = 3;
UPDATE employees SET deptno = 2,salary = salary + 1000 WHERE empno = 3;
SELECT * FROM employees WHERE empno = 3;
-- 更新数据为默认值
SELECT * FROM employees WHERE empno = 3;
UPDATE employees SET salary = DEFAULT WHERE empno = 3;
SELECT * FROM employees WHERE empno = 3;
-- UPDATE中使用子查询
SELECT * FROM employees WHERE
deptno = (SELECT deptno FROM departments WHERE managerno = 2);
UPDATE employees SET salary = salary +100
WHERE deptno = (SELECT deptno FROM departments WHERE managerno = 2);
SELECT * FROM employees WHERE
deptno = (SELECT deptno FROM departments WHERE managerno = 2);
DELETE是用于删除表中的行项目,语法 DELETE FROM 表名称 WHERE 列名称 = 值;当然也可以不加WHERE条件,那这样就是删除表的所有行数据内容,不删除定义也不释放空间,表的结构、属性和索引都还是完整的。如果使用DELETE删除所有表数据,再向表中新增3条数据,id将从之前的id继续进行递增,就有可能看到表中id是不连续的。
-- DELETE的用法
SELECT * FROM employees;
INSERT INTO employees(empno,name,salary) VALUES(11,'test',9999);
SELECT * FROM employees;
DELETE FROM employees WHERE empno = 11;
SELECT * FROM employees;
-- DELETE中使用子查询
SELECT * FROM departments;
SELECT * FROM employees WHERE deptno IN
(SELECT deptno FROM departments WHERE loc = '二楼');
DELETE FROM employees WHERE deptno IN
(SELECT deptno FROM departments WHERE loc = '二楼');
TRUNCATE也是删除表数据,TRUNCATE TABLE = DELETE FROM TABLE 但是TRUNCAT的效率更高,DELETE是一条条收回/删除,TRUNCAT是整张表收回/删除。并且TRUNCATE是会删除内容和释放空间的(不删除定义),如果使用TRUNCATE删除表数据后,再向表中新增3条数据,那么这三条数据的id将分别重新定义为1、2、3,这体现其释放空间的特性。但是需要注意使用TRUNCATE是无法删除行数据的,只能清空整张表数据。TRUNCATE也不会触发任何DELETE触发器。
-- TRUNCATE TABLE = DELETE FROM TABLE
TRUNCATE TABLE
DELETE FROM TABLE
DROP TABLE可以理解为真·删除表,它会删除表数据和定义、释放空间,删除后这个表的所有东西都没有了。删除程度:DROP > TRUNCATE > DELETE
-- DROP TABLE 就是DROP 表名称 就能删除
DROP TABLE
LIKE操作符可以在WHERE条件中对列进行指定的匹配,例如搜索所有姓李的员工就可以使用LIKE,当然如果是NOT LIKE,也可以筛选出所有不姓李的员工。
-- LIKE的用法,%表示任意长度字符,_表示一个字符长度
SELECT * FROM employees WHERE name LIKE '李%';
SELECT * FROM employees WHERE name LIKE '%卫%';
SELECT * FROM employees WHERE email LIKE '__a%';
SELECT * FROM employees WHERE email LIKE '%qq.com';
IN操作符就是可以使WHERE条件中存在多个值,例如选取员工号empno为3、5、6的员工,示例的前两句的执行结果是相同的。
-- IN的用法
SELECT name, empno FROM employees WHERE empno = 3 OR empno = 5 OR empno = 6;
SELECT name, empno FROM employees WHERE empno IN (3,5,6);
SELECT name, empno FROM employees WHERE empno NOT IN (3,5,6);
-- 当子查询有多行时需要用IN
SELECT * FROM employees WHERE
deptno IN (SELECT deptno FROM departments WHERE managerno = 2 OR managerno = 3);
BETWEEN AND用于选择介于两个值之间的范围,常用在日期或数值上,例如查找2023年入职的员工就可以使用hiredate BETWEEN '2013-01-01' AND '2013-12-31'
-- BETWEEN的用法
SELECT name,hiredate FROM employees
WHERE hiredate >= '2013-01-01' AND hiredate <= '2013-12-31';
SELECT name,hiredate FROM employees
WHERE hiredate BETWEEN '2013-01-01' AND '2013-12-31';
SELECT name,hiredate FROM employees
WHERE hiredate NOT BETWEEN '2013-01-01' AND '2013-12-31';
ORDER BY用于对筛选结果进行排序,默认是ASC升序,如果需要使用降序要指定DESC关键字,且支持对多个字段进行排序,只需要在句子后加上ORDER BY 列1,列2 DESC就会按列1升序和列2降序进行排列。
-- ORDER BY的用法,默认为ASC升序,加上DESC则为降序,可以使用别名进行排序
SELECT name,salary FROM employees ORDER BY salary;
SELECT name,salary FROM employees ORDER BY salary ASC;
SELECT name,salary FROM employees ORDER BY salary DESC;
-- 使用多个字段进行排序,同样可以使用ASC和DESC
SELECT name,deptno,salary FROM employees ORDER BY deptno,salary;
SELECT name,deptno,salary FROM employees ORDER BY deptno DESC,salary ASC;
GROUP BY用于根据一个或者多个列进行分组,如果同时需要分组和排序,注意需要先GROUP BY再ORDER BY,否则会错误提示。例如示例为按照部门分组,筛选各部门的最高工资、最低工资等数据。
-- GROUP BY的用法
SELECT
deptno,
MAX( salary ) AS 最高工资,
MIN( salary ) AS 最低工资,
SUM( salary ) AS 汇总工资,
CAST(AVG( salary ) AS DECIMAL ( 10, 2 )) AS 平均工资2位小数,
COUNT(*) AS 员工数
FROM employees
WHERE hiredate > '2010-01-01'
GROUP BY deptno
ORDER BY 平均工资2位小数;
在使用SELECT进行查询的时候,为列和表指定别名,可以令列的输出名称更易读,使表的使用更便捷等。在使用AS的时候也可以隐藏,直接SELECT 列名称 别名 FROM 表。
-- AS的使用 指定输出列名
SELECT empno AS 员工号,salary 月薪, salary*14 14薪 FROM employees;
-- AS的使用 指定表的别名
SELECT name,dname,e.deptno FROM employees AS e,departments d
WHERE e.deptno = d.deptno;
通常每张数据库表都会存储与其定义相关的内容,但是在业务中我们所需的数据经常都无法从一张表里就取出,我们需要连接两张表甚至更多表来获取想要的数据,这时候就需要使用JOIN进行表连接。表连接有多种INNER JOIN内连接、LEFT JOIN左连接、RIGHT JOIN右连接、FULL JOIN全连接(不过MySQL不支持FULL JOIN)等,而内连接INNER JOIN我们也常省略INNER写作JOIN。
-- 传统的多表连接
SELECT name,dname FROM employees,departments
WHERE employees.deptno = departments.deptno;
SELECT * FROM employees,departments
WHERE employees.deptno = departments.deptno;
-- 直接从两表取所有的数得到的数据量会是两个表相乘的数量
SELECT * FROM employees,departments;
-- 两个表的重名字段deptno会报错,需要指定表名,常用的也有使用表的别名
SELECT name,dname,employees.deptno FROM employees,departments
WHERE employees.deptno = departments.deptno;
SELECT name,dname,e.deptno FROM employees e,departments d
WHERE e.deptno = d.deptno;
-- 三个表的连接
SELECT job_history.*,employees.name,departments.dname
FROM job_history,employees,departments
WHERE job_history.empno = employees.empno
AND job_history.deptno = departments.deptno;
INNER JOIN 内连接
-- INNER JOIN内连接
SELECT name,dname,e.deptno FROM employees e,departments d
WHERE e.deptno = d.deptno;
-- JOIN的方式有多种,默认采用的就是INNER JOIN,所以可以省略
SELECT name,dname,e.deptno FROM employees e
INNER JOIN departments d ON e.deptno = d.deptno;
SELECT name,dname,e.deptno FROM employees e
JOIN departments d ON e.deptno = d.deptno;
内连接可以连接自身,但是需要用到刚才提到的AS别名,将一张表分别取为两个别名,这样就能进行自连接查询数据,使用场景在这个数据库中可以例如查询同名的员工或在同一个部门共事过的员工
-- 查询同名的员工
-- INSERT INTO employees(empno,name,deptno) VALUES(11,'刘德华',5);
SELECT e1.empno,e1.name
FROM employees e1 JOIN employees e2
ON e1.name = e2.name AND e1.empno != e2.empno
ORDER BY e1.empno;
-- 查询在同一个部门共事过的员工
SELECT j1.empno,j2.empno,j1.deptno,j1.start_date comm_start
FROM job_history j1 JOIN job_history j2
ON j1.deptno = j2.deptno AND j1.empno != j2.empno
AND j1.start_date BETWEEN j2.start_date AND j2.end_date;
外连接
-- 内连接 INNER JOIN 两边符合条件
SELECT e.empno,name,dname,e.deptno
FROM employees e JOIN departments d
ON e.deptno = d.deptno;
-- 左连接 LEFT JOIN 以左侧表为主,右侧表与其相匹配,匹配不上的记录 ,以null 做替补
SELECT e.empno,name,dname,e.deptno
FROM employees e LEFT JOIN departments d
ON e.deptno = d.deptno;
-- 右连接 RIGHT JOIN 以右侧表为主,左侧表与其相匹配,匹配不上得记录,以null做替补
SELECT e.empno,name,dname,d.deptno
FROM employees e RIGHT JOIN departments d
ON e.deptno = d.deptno;
-- 全连接 FULL JOIN(MySQL和SQLite不支持FULL JOIN)
SELECT e.empno,name,dname,d.deptno
FROM employees e FULL JOIN departments d
ON e.deptno = d.deptno;
-- 三表进行左外连接
SELECT e.name,e.deptno,d.managerno,j.deptno
FROM employees e LEFT JOIN departments d ON e.deptno = d.deptno
LEFT JOIN job_history j ON e.empno = j.empno AND e.deptno != j.deptno;
-- 连接查询时如果是同名字段作为连接条件,using可以代替on出现,提高查询效率
-- USING是针对同名字段(using(id) === on A.id=B.id)
-- 例如左连接中可改写为,USING (deptno);
交叉连接 CROSS JOIN
-- CROSS JOIN交叉连接
-- 相当于两个表的笛卡尔积,等于两个表的记录数相乘
-- 表1有4条记录,表2有5条记录,交叉连接后有20条数据
SELECT * FROM employees CROSS JOIN departments;
SELECT * FROM employees,departments;
UNION主要是用来两个或多个SELECT语句的结果。UNION会选择不同的值,如果查询的记录中有重复的值需要使用UNION ALL。注意:使用UNION列数必须相同,且对应列的属性也相同
-- UNION集合 UNION显示不重复的,UNION ALL重复的也会显示
-- 使用UNION列数必须相同,且对应列的属性也相同
SELECT empno,deptno FROM employees;
SELECT managerno,deptno FROM departments;
SELECT empno,deptno FROM employees
UNION
SELECT managerno,deptno FROM departments;
SELECT empno,deptno FROM employees
UNION ALL
SELECT managerno,deptno FROM departments;
-- UNION的使用场景,筛选高、中、低三个工资档位的员工,不过一般也不会写这么复杂的三句查询
SELECT name,salary,'低薪' AS 工资档次 FROM employees WHERE salary < 10000
UNION
SELECT name,salary,'中薪' AS 工资档次 FROM employees WHERE salary BETWEEN 10000 AND 20000
UNION
SELECT name,salary,'高薪' AS 工资档次 FROM employees WHERE salary > 20000
-- INTERSECT 取出两个表不同的部分(不过mysql不支持INTERSECT)
SELECT empno,deptno FROM employees
INTERSECT
select managerno,deptno FROM departments;
HAVING的效果和WHERE差不多都是进行条件过滤的,只不过WHERE无法和聚合函数一起使用,因为SQL会先执行WHERE再执行GROUP BY,需要理解下他们的语法及执行顺序。
-- HAVING过滤分组,类似于WHERE
-- 但是执行在GROUP BY之后,需要HAVING的条件字段或聚合函数需要在SELECT中出现
SELECT deptno,AVG(salary) 平均工资 FROM employees GROUP BY deptno;
-- 下面这个执行会报错,因为此时还没有平均工资这一列,它先执行where,再来执行GROUP BY
-- SELECT deptno,AVG(salary) 平均工资 FROM employees
-- WHERE 平均工资 > 10000 GROUP BY deptno;
-- 需要改写为
SELECT deptno,AVG(salary) 平均工资 FROM employees
GROUP BY deptno
HAVING 平均工资 > 10000;
NULL是空值,某个值显示为空不一定等于NULL,在创建表时如果在某个字段后加上NOT NULL,则表示强制该列不接受空值,若为空则为提示错误。NULL也是一个条件,但是在使用的时候需要用IS NULL或IS NOT NULL来进行过滤,而不能使用= NULL。
-- NULL空值,为空不等于NULL,判断一个值为NULL要用IS NULL
-- 在MySQL和SQL Server为NULL时会显示NULL,而在Oracle和PostgreSQL会显示空
SELECT 1 WHERE NULL IS NULL;
SELECT 1 WHERE NULL IS NOT NULL;
SELECT 1 WHERE '' IS NOT NULL;
在数据中存在NULL时往往需要特别注意,如果这个列中存在NULL值,用这列去比较的时候有可能会出现问题。
-- 假设需要查询没有员工的部门,
-- 下面语句因为e.deptno中存在空值,所以用d.deptno去比较的话会比不出来
SELECT deptno,dname from departments d
WHERE d.deptno NOT IN
(SELECT e.deptno FROM employees e);
-- 因此需要改写为
-- 方法一
SELECT deptno,dname FROM departments
WHERE departments.deptno NOT IN
(SELECT employees.deptno FROM employees
WHERE employees.deptno IS NOT NULL);
-- 方法二
SELECT deptno,dname FROM departments
WHERE NOT EXISTS
(SELECT 1 FROM employees WHERE departments.deptno = employees.deptno);
-- 方法二不一定好理解,在这里解释一下
-- 外层查询:SELECT deptno, dname FROM departments
-- 这是外层查询,从"departments"表中选择部门号(deptno)和部门名称(dname)。
-- 内层查询:SELECT 1 FROM employees WHERE departments.deptno = employees.deptno
-- 这是内层查询,它用于检查是否存在与外层查询结果中的部门号相匹配的记录。如果存在匹配的记录,将返回1;否则,返回空。
-- 条件:WHERE NOT EXISTS
-- 这是外层查询的条件子句,它使用了"NOT EXISTS"来判断内层查询的结果是否为空。如果内层查询的结果为空,表示在"employees"表中不存在与外层查询结果中的部门号相匹配的记录。
视图简单来说也可以理解为对SQL语句的结果集的可视化表,视图中的数据来自一个活多个真实表,且视图本身不保存数据。我们可以像查询一个表一样来查询视图,查询视图时数据库也是通过执行创建视图时的那些SQL语句来返回结果,并且如果那些真实表中的数据更改,视图的数据也会进行更改,视图显示的是当前的数据,因此如果更新一些简单的视图(没有集合、没有DISTINCT、没有聚合函数、没有GROUP BY、没有多表连接),表中的数据也会被更改。
-- 视图的用法,筛选所有的部门经理的员工信息视图
CREATE VIEW emp AS
(SELECT * FROM employees WHERE empno IN
(SELECT managerno FROM departments))
当具有多个条件进行匹配的时候也常用到CASE WHEN表达式
-- 方法一
-- CASE 字段
-- WHEN 值 THEN 结果
SELECT empno,deptno,
CASE deptno
WHEN 1 THEN '开发部'
WHEN 2 THEN '测试部'
WHEN 3 THEN '销售部'
ELSE '其他部门'
END deptname
FROM employees;
-- 方法二
-- CASE
-- WHEN 字段 = 值 THEN 结果
SELECT empno,deptno,
CASE
WHEN deptno = 1 THEN '开发部'
WHEN deptno = 2 THEN '测试部'
WHEN deptno = 3 THEN '销售部'
ELSE '其他部门'
END deptname
FROM employees;
-- 之前在UNION中讲到的,使用UNION连接三个SELECT语句就可以改写为
SELECT name,salary,
CASE
WHEN salary < 10000 THEN '低薪'
WHEN salary BETWEEN 10000 AND 20000 THEN '中等'
ELSE '高薪'
END '工资档次'
FROM employees ORDER BY salary;
很好理解,ALL表示所有,ANY代表任何,在一些最大最小值的时候常用到
-- ALL关键字 俩俩分别表示同一结果
SELECT name FROM employees
WHERE salary > (SELECT MAX(salary) FROM employees WHERE deptno = 1);
SELECT name FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE deptno = 1);
SELECT empno,name FROM employees
WHERE empno NOT IN
(SELECT managerno FROM departments WHERE managerno IS NOT NULL);
SELECT empno,name FROM employees
WHERE empno != ALL
(SELECT managerno FROM departments WHERE managerno IS NOT NULL);
-- ANY关键字 俩俩分别表示同一结果
SELECT empno,name FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees WHERE deptno = 2);
SELECT empno,name FROM employees
WHERE salary < ANY (SELECT salary FROM employees WHERE deptno = 2);
SELECT name FROM employees
WHERE empno IN (SELECT DISTINCT managerno FROM departments);
SELECT name FROM employees
WHERE empno = ANY (SELECT DISTINCT managerno FROM departments);
EXISTS即存在的意思,和IN是类似的,考虑执行效率时,如果子查询记录多适合使用EXISTS,如果主查询记录多适合使用IN。
SELECT name FROM employees
WHERE empno IN
(SELECT DISTINCT empno FROM job_history);
SELECT name FROM employees
WHERE EXISTS
(SELECT empno FROM job_history WHERE employees.empno = job_history.empno);
SELECT name FROM employees
WHERE empno NOT IN
(SELECT DISTINCT empno FROM job_history);
SELECT name FROM employees
WHERE NOT EXISTS
(SELECT empno FROM job_history WHERE employees.empno = job_history.empno);
返回该列中的最大值(也可用于文本,将按字母顺序进行排列大小),NULL不会被用于计算。
语法为SELECT MAX(列名) FROM 表名;
SELECT MAX( salary ) AS 最高工资 FROM employees;
返回该列中的最小值(也可用于文本,将按字母顺序进行排列大小),NULL不会被用于计算。
语法为SELECT MIN(列名) FROM 表名;
SELECT MIN( salary ) AS 最低工资 FROM employees;
返回该列数值的总和。
语法为SELECT SUM(列名) FROM 表名;
SELECT SUM( salary ) AS 汇总工资 FROM employees;
返回该列数值的平均值,NULL不会被用于计算。
语法为SELECT AVG(列名) FROM 表名;
SELECT AVG( salary ) AS 平均工资 FROM employees;
返回指定条件的行数量。
语法为SELECT COUNT(列名) FROM 表名;
SELECT COUNT(*) AS 员工数 FROM employees;
SELECT COUNT(deptno) AS 部门数 FROM employees;
SELECT COUNT(DISTINCT deptno) AS 部门数 FROM employees;
在进行一些计算的时候有可能会需要数值类型转换,例如下面例子中计算所有人的平均工资,如果不进行数值转换则会有多位小数,显然是不满足工资2位小数的实际业务需求。
语法CAST(列名 AS 数据类型)
SELECT
CAST(AVG(salary) AS DECIMAL(10,2)) AS 平均工资2位小数
FROM employees;
附一些数据类型
值 | 描述 |
---|---|
DATE | 日期,格式为 'YYYY-MM-DD'. |
DATETIME | 日期加具体的时间,格式为 'YYYY-MM-DD HH:MM:SS'. |
TIME | 时间,格式为 'HH:MM:SS'. |
CHAR | 字符型 |
SIGNED | int |
UNSIGNED | 无符号int |
BINARY | 二进制型 |
DECIMAL | float型 |
关于数据库方面还有很多内容可以写,以上只是基础使用和语法,有空了再继续进行学习分享和记录。
(仅为个人记录,如有错误请指正,感谢!)