连接查询,子查询

连接查询(不加条件时是笛卡尔积)

1内连接
1.1等值连接
1.2非等值连接
1.3自连接
2.外连接
2.1左外连接
2.2右外值连接
3.交叉连接
分类(按照功能):

  1. 内连接: inner
    等值连接
    非等值连接
    自身连接
  2. 外连接:
    左外连接 left
    右外连接 right
    全外连接(不支持)
  3. 交叉连接 cross

内连接

等值连接

  • 等值连接时若多次使用表名或表名过长,可为表起别名
    eg:from employees e,iob_id j
  • sq99中from employees e join iob_id j用)(连接类型)join替换“,”连接条件用 on 来表示,筛选单独用where,增加了可读性
  • 注意:
  1. 这样可以提高语句简洁度,区分多个同名字段
  2. 另外哦使用别名后就不能再使用别名
  • 等值连接实例:
    eg:查询有奖金的员工名字和部门名
select last_name,department_name,commission_pct
from employees e,departments d
where e.department_id = d.department_id
and e.commission_pct is not null; 

eg:查询城市名中第二个字符o的部门名和城市名:

SELECT department_name,city
FROM departments d,locations l
WHERE d.location_id = l.location_id 
AND city LIKE '_o%';

eg:查询每个工种的工种名和员工个数,并且按员工个数降序

//1
SELECT job_title,COUNT(*) _count
FROM jobs j,employees e
WHERE e.job_id=j.job_id
GROUP BY job_title
ORDER BY _count DESC;

eg:(sq99中)查询员工名,部门名,工种名,按部门名降序

//2
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d 
ON e.department_id=d.department_id
INNER JOIN jobs j
ON e.job_id=j.job_id
ORDER BY department_name DESC;

eg:查询有奖金的每个部门的部门名和部门领导编号和该部门的最低工资

SELECT department_name,d.manager_id,MIN(salary)
FROM  employees e,departments d
WHERE e.department_id = d.department_id 
AND commission_pct IS NOT NULL
GROUP BY department_name,d.manager_id;
  • 实现三表查询:
    **注意:**应该类似这样写,而不是连等于,即n表连接需要n-1连接条件:
where e.department_id = d.department_id
and d.location_id = l.location_id

非等值连接

eg:查询员工的工资和工资级别 ``` SELECT salary,grade_level FROM employees e,job_grades g WHERE salary BETWEEN g.lowest_sal AND g.highest_sal; ```

自连接

连接条件是自己本身表中的某列值
给表名取若干个别名,讲一张表变成多张表

eg:查询员工们和上级的名称

SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.manager_id = m.employee_id;

外连接

> **用于查询一个表中有一个表中没有的 > 特点:外连接的查询结果是主表中所有记录 > 从表若有和其匹配,就显示配置值(相当于内连接) > 若无,显示null > 左外:left join左边是主表 > 右外:right join右边是主表**

左外连接

eg:

select b.name
from beauty b
left outer join boys bo
on b.boyfriend_id = bo.id
where bo.id is null;

eg:查询没有员工的部门

SELECT department_name
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;

右外连接

eg:拿左外的例二做比: ``` SELECT department_name FROM employees e RIGHT OUTER JOIN departments d ON d.department_id = e.department_id WHERE e.employee_id IS NULL; ```

交叉连接

> 就是笛卡尔积

eg:

SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;

典型例子

eg:查询部门名为sal和it的员工信息
可能有没有员工的部门,所以不能用内连接

SELECT e.*,d.department_name
FROM departments d
LEFT OUTER JOIN employees e
ON e.department_id = d.department_id
WHERE d.department_name IN ('SAL','IT');

子查询

含义:出现在其他语句内部的select语句,称为子查询或者内查询
外部的查询称为主查询或外查询

分类:

  • 按子查询出现位置:
    1. select后:支持标量子查询
    2. from后:支持表子查询
    3. where或having后:支持标量子查询,列子查询,行子查询
    4. exists后(相关子查询):支持表子查询
  • 按结果集的行列数不同:
    1. 标量子查询(结果集一行一列)
    2. 列子查询(结果集一列多行)
    3. 行子查询(结果集一行多列)
    4. 表子查询(结果集多行多列)

标量子查询(单行子查询)

子查询一般在条件右边
搭配单行操作符使用(>,<,>=,…)
子查询优先执行

eg:可以使用多个子查询并列

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
)

但必须保证子查询结果只有一个,否则报错
错误例子eg:

SELECT MIN(salary),department_id

FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT salary
	FROM employees
	WHERE department_id = 50
);

搭配多行操作符使用(in,any,all,some)

1. select后

eg:查询每个部门的员工个数:

SELECT d.*,(
	SELECT COUNT(*)
	FROM employees e
	WHERE d.department_id = e.department_id
)_count
FROM departments d;

eg:查询员工号为102的部门名:

//我认为有点强求,实际上外层select只是起到起别名的作用而已
select (
	SELECT d.department_name
	FROM departments d,employees e
	WHERE d.department_id = e.department_id
	AND e.employee_id = 102
) 部门名;
//前边起别名也可以
	SELECT d.department_name 部门名
		FROM departments d,employees e
		WHERE d.department_id = e.department_id
		AND e.employee_id = 102;
//实际上我用where后的子查询也可以起到相同作用
	SELECT d.department_name
	FROM departments d
	WHERE d.department_id = (
		SELECT e.department_id
		FROM employees e
		WHERE e.employee_id = 102
);

2. from后

跟在from的感觉更像是把这个子查询的结果集当作一张新表去使用,需要注意的是: 此时必须为这张新表取别名!!!

eg:查询每个部门的平均工资和等级:

SELECT ag_dep.*,grade_level
FROM(
	SELECT AVG(e.salary) avg_sa,e.department_id
	FROM employees e
	GROUP BY department_id
	) ag_dep,job_grades g
WHERE ag_dep.avg_sa BETWEEN lowest_sal AND highest_sal;

eg:查询各个部门中工资比本部门平均工资高的员工的工号,姓名,工资:

//按题目要求
SELECT e.employee_id,e.last_name,e.salary
FROM employees e,(
	SELECT AVG(salary) _avg,department_id
	FROM employees 
	GROUP BY department_id
) avg_de
WHERE e.department_id = avg_de.department_id
AND e.salary > avg_de._avg;
//我自己觉得加上部门名字会更直观,但是为了这个我们需要内连接的表多了一个
SELECT department_name,d.department_id,e.employee_id,e.last_name,e.salary
FROM departments d,employees e,(
	SELECT AVG(salary) _avg,department_id
	FROM employees 
	GROUP BY department_id
) avg_de
WHERE d.department_id = avg_de.department_id
AND d.department_id = e.department_id
AND e.salary > avg_de._avg;

3. exists后

又叫做相关子查询,他实际上是先执行外层的查询,然后再执行内层的子查询
其语法是 exists (完整查询语句)
它查的其实是这个语句的存在性,结果是1代表存在,0是不存在

eg:查询有员工的部门名:

//我的方法并没有用到嵌套查询
SELECT d.department_name
	FROM departments d
	LEFT OUTER JOIN employees e
	ON d.department_id = e.department_id
	WHERE e.employee_id IS NOT NULL;

利用exists的方法意思是在departments表里依次取department_id去检查employees表,若employees中存在这样一个元祖,二者department_id匹配时,就去departments中的name显示出来:

SELECT d.department_name
FROM departments d
WHERE EXISTS(
	SELECT *
	FROM employees e
	WHERE d.department_id = e.department_id	
);

其实还可以用where后嵌套查询的方法更简单:

SELECT d.department_name
FROM departments d
WHERE d.department_id IN(
	SELECT e.department_id
	FROM employees e
);

4. where或having后(having后语法和where一致,只是用筛选后条件而已)

where xx in(…)
where xx not in(…)
where xx =(…)[子查询必须为单行]
where xx >(…)[子查询必须为单行]
…[子查询必须为单行单行]
where xx >any(…)[大于子查询结果中的某个值]

where xx >all(…)[大于子查询结果中的所有值]

eg:

SELECT d.department_name
	FROM departments d
	LEFT OUTER JOIN employees e
	ON d.department_id = e.department_id
	WHERE e.employee_id IS NOT NULL;

eg:查询平均工资高于公司平均工资的部门:

SELECT  e.department_id
FROM employees e
GROUP BY e.department_id
HAVING AVG(salary) > (
	SELECT AVG(salary)
	FROM employees
);

5.有趣例子

eg:查询平均工资最低的部门信息和该部门的平均工资:

SELECT d.*,a._avg
FROM departments d,(
	SELECT AVG(salary) _avg,e.department_id
	FROM employees e
	GROUP BY e.department_id
	ORDER BY _avg
	LIMIT 1
) a// 记着取别名!!!
WHERE d.department_id = a.department_id;
  • ’in’ 相当于 '= any’
  • GROUP BY 后边可以加几个列名

eg:各个部门中最高工资中最低的那个部门的最低工资是多少:

SELECT MIN(salary)
FROM employees e
WHERE e.department_id = (
	SELECT e.department_id
	FROM employees e
	GROUP BY e.department_id
	ORDER BY MAX(salary)
	LIMIT 1
);
发布了46 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yuanfangyoushan/article/details/90146014