从零开始数据库阶段一(三)

1. 基础部分

GROUP BY

SQL原语:SELECT column_name, aggregate_function(column_name) FROM table_name
WHERE column_name operator value GROUP BY column_name;

  GROUP BY适合多表组合,一个column有多个相同的值,按照该值进行分组并使用聚合函数获取所需的信息,具体实例参考后面。

WITH ROLLUP可以实现在分组统计数据基础上再进行相同的统计(SUM,AVG,COUNT…)。

NULL值处理

  • IS NULL: 当列的值是 NULL,此运算符返回 true。
  • IS NOT NULL: 当列的值不为 NULL, 运算符返回 true。
  • <=>: 比较操作符(不同于=运算符),当比较的的两个值为 NULL 时返回 true。

  特别注意不能使用 = NULL 或 != NULL 在列中查找 NULL 值。只能使用上面列出的方法来判断NULL值。

MySQL 正则表达式

模式 描述
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。
. 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用象 ‘[.\n]’ 的模式。
[…] 字符集合。匹配所包含的任意一个字符。
[^…] 负值字符集合。匹配未包含的任意字符。
p1|p2|p3 匹配 p1 或 p2 或 p3。
* 匹配前面的子表达式零次或多次。
+ 匹配前面的子表达式一次或多次。。
{n} n 是一个非负整数。匹配确定的 n 次。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。

2. 实例练习

2.1

查找最晚入职员工的所有信息

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)); 

  从表的信息可知,按照hire_date降序排列并返回第一条信息:

SELECT * FROM employees ORDER BY hire_date DESC LIMIT 1;

  如果最晚入职的员工记录有多条,上面的语句会漏掉信息,所以采用下面的方式:

SELECT * FROM employees WHERE hire_date=(SELECT MAX(hire_date) FROM employees);
---这种使用方式要保证后面的SELECT语句只返回一行,一列。

查找入职员工时间排名倒数第三的员工所有信息

  表的结构没有变,现在需要获取倒数第三名员工的信息,需要使用排序原语:

SELECT * FROM employees ORDER BY hire_date DESC LIMIT 2,1;
---LIMIT 的用法:
---后面一个参数a时,返回a条记录
---后面两个参数a,b时,返回从a+1的b条记录

2.2

查找各个部门当前(to_date=’9999-01-01’)领导当前薪水详情以及其对应部门编号dept_no

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

  希望查询的信息位于两个表中,使用JOIN来解决这个问题:

SELECT  b.*,a.dept_no FROM salaries b,dept_manager a WHERE a.emp_no=b.emp_no AND b.to_date='9999-01-01' AND a.to_date='9999-01-01';  
---INNER JOIN和WHERE等价

  这里基于两个思考:首先,dept_manager可能有一个员工多次的记录(比如人事调动),salaries可能有一个员工多次的记录(比如薪水调整)。然后,使用JOIN的结果势必造成多次重复,假设A表中有一个员工的有n次记录,B表中该员工有m次记录,使用员工号相等条件的JOIN查询,结果该员工将有nm次记录。

2.3

查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

  首先应该想到有的员工并没有分配部门,为了得到这一信息需使用LEFT JOIN,因为该命令返回左表的所有信息,如果查询条件不满足则置空一些列,如下:

SELECT b.last_name,b.first_name,a.dept_no FROM  employees b LEFT JOIN dept_emp a ON b.emp_no=a.emp_no 

获取所有非manager的员工emp_no

  非管理层员工的特点就是employees有记录,而dept_emp没有记录。所以使用LEFT JOIN来查询这一信息:

SELECT emp_no FROM (SELECT * FROM employees b LEFT JOIN dept_manager a ON a.emp_no=b.emp_no) WHERE dept_no IS NULL;

2.4

查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

  特别注意是入职的时候的情况,且所查询的信息分布在两个表中,需要使用JOIN,这里我喜欢使用WHERE等价代替:

SELECT  a.emp_no,b.salary FROM employees a,salaries b WHERE a.emp_no=b.emp_no AND a.hire_date=b.from_date ORDER BY a.emp_no DESC;

2.5

查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

  将每一个员工看成一个分组,然后使用聚合函数得到条目信息总数,因为WHERE后面不能使用聚合函数,所以使用HAVING:

SELECT emp_no,COUNT(*) FROM salaries GROUP BY emp_no HAVING COUNT(*)>15;

3. 小结

  经过实例练习,熟悉了查询命令中各种语法的使用场景和使用方式。之后的就可以学习索引和其他概念,并进行相应的练习。

猜你喜欢

转载自blog.csdn.net/LoveStackover/article/details/81007423