多表查询与子查询
问题的引出:
这里有一个留言板,其中一条评论包含了商品名称good(商品表),留言content(留言表)。 那么请问如将这个评论从数据库查询出来?这就涉及到了多表查询。
多表查询是指基于两个和两个以上的表查询.在实际应用中,查询单个表可能不能满足你的需求。
笛卡尔集
首先新建三张表并插入测试数据
#新建一张部门表
create table dept (
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
dname varchar(20) not null default '',
loc varchar(13) not null default '');
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK'),(20,'RESEARCH','DALLAS'),(30,'SALES','CHICAGO'),(40,'OPERATIONS','BOSTON');
#新建一张员工表
create table emp (
empno MEDIUMINT unsigned not null default 0,
ename varchar(20) not null default '', /* 名字*/
job varchar(9) not null default '',
mgr mediumint unsigned , /* 上级编号*/
hiredate date not null, /* 入职时间*/
sal decimal (7,2) not null , /* 薪水*/
comn decimal(7,2), /* 红利*/
deptno MEDIUMINT unsigned not null default 0); /* 部门编号*/
INSERT INTO emp VALUES (7369,'SMITH','CLERK', 7902, '1990-12-17', 800.00, NULL , 20);
INSERT INTO emp VALUES ( 7499,'ALLEN' , 'SALESMAN', 7698, '1991-2-20', 1600.00, 300.00, 30);
INSERT INTO emp VALUES (7521,'WARD','SALESMAN', 7698,'1991-2-22', 1250.00, 500.00, 30);
INSERT INTO emp VALUES (7566,'JONES','MANAGER', 7839,'1991-4-2', 2975.00, NULL, 20);
INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'1991-9-28',1250.00,1400.00,30);
INSERT INTO emp VALUES (7698, 'BLAKE', 'MANAGER', 7839,'1991-5-1', 2850.00, NULL, 30);
INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'1991-6-9',2450.00,NULL,10);
INSERT INTO emp VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1997-4-19', 3000.00, NULL, 20);
INSERT INTO emp VALUES (7839, 'KING', 'PRESIDENT' , NULL, '1991-11-17' , 5000.00, NULL,10);
INSERT INTO emp VALUES (7844,'TURNER', 'SALESMAN', 7698, '1991-9-8', 1500.00, NULL, 30);
INSERT INTO emp VALUES (7900, 'JAMES', 'CLERK' , 7698, '1991-12-3', 950.00, NULL, 30);
INSERT INTO emp VALUES (7902,'FORD', 'ANALYST', 7566, '1991-12-3', 3000.00, NULL, 20);
INSERT INTO emp VALUES (7934,'MILLER' , 'CLERK', 7782,'1992-1-23', 1300.00,NULL, 10) ;
SELECT * from emp;
#工资级别表
CREATE TABLE salgrade
(
grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, -- 级别
losal DECIMAL(17,2) NOT NULL, -- 该级别最低工资
hisal DECIMAL(17,2) NOT NULL); -- 该级别最高工资
RENAME TABLE salgradegrade TO salgrade;
INSERT INTO salgrade VALUES(2, 1201, 1400);
INSERT INTO salgrade VALUES(3,1401, 2000);
INSERT INTO salgrade VALUES(4, 2001, 3000);
INSERT INTO salgrade VALUES(5,3001,9999);
INSERT INTO salgrade VALUES(1,700,1200);
?显示部门、工资、及所在部门的名称
分析:显示部门编号、工资 需要 查询emp表
显示部门名称需要查询 dept 表
在不加where子句的情况下, 先来看 select * from emp,dept (查询两张表用逗号隔开) 返回的结果。总共52条记录。
那么这52条记录是如何查出来的呢? 从结果来看,每一个员工都对应了所有部门。
?显示部门、工资、及所在部门的名称
在笛卡尔积当中,一个员工对应了4个部门,我们只需要部门编号deptno相等的那个部门,所以加上where子句进行过滤。
SELECT emp.deptno,sal,dept.dname from dept,emp where emp.deptno = dept.deptno
多表查询
多表查询SQL书写思路 : 首先要对表结构高度熟悉。 先用?代替select的具体colunm, 然后考虑需要查询的表是哪几张(from),再考虑筛选条件(where)
-- 显示各个员工的姓名,工资,及其工资的级别
SELECT ename,sal,salgrade.grade
from emp,salgrade
where sal BETWEEN salgrade.losal AND salgrade.hisal
-- 如何显示部门号为10的部门名、员工名和工资
SELECT dept.dname,ename,sal ,emp.deptno from dept,emp
where emp.deptno = dept.deptno AND emp.deptno=10;
-- 显示雇员名,雇员工资及所在部门的名字,并按部门排序[降序排].
SELECT ename,sal,dept.dname
from emp, dept
where emp.deptno = dept.deptno
ORDER BY emp.deptno desc;
自连接
自表连接是指在同一张表上的连接查询。
? 显示公司员工和他的上级的名字
-- 显示公司员工和他的上级的名字
SELECT temp.ename , emp.ename as boss
from emp ,emp as temp
where emp.empno = temp.mgr
子查询
概念 : 子查询是指嵌入在其它sql语句中的select语句,也叫嵌套查询
单行子查询
单行子查询是指只返回一行数据的子查询语句。
-- 如何显示与smith在同一个部门的员工
SELECT * from emp where deptno = (
SELECT deptno FROM emp
where ename = 'SMITH');
多行子查询
多行子查询指返回多行数据的子查询, 使用关键字in
-- 如何查询和部门10的工作相同的雇员的名字、岗位、工资、部门号,但是不含10号部门自己的雇员
-- 分析 首先查10 部门的job
SELECT job from emp where deptno = '10';
--然后使用子查询
SELECT ename,job,sal,deptno from emp where job in (
SELECT job from emp
where deptno = '10'
)
and deptno != 10;
子查询临时表
先创建一张商品表并插入测试数据
CREATE TABLE goods_l (
goods_id INT,
cat_id INT,
goods_name VARCHAR(32),
shop_price DOUBLE );
insert into goods_l VALUES
(1,2,'奥利奥',15.00),
(2,2,'好丽友',20.00),
(3,3,'卫龙',2.00),
(4,3,'巧乐兹',5.00),
(5,4,'可爱多',5.00),
(6,4,'东方树叶',5.00);
-- 查询ecshop中各个类别中,价格最高的商品
-- 查询ecshop中各个类别中,价格最高的商品.
-- 分析先查询出 各个类别中的 价格最高
SELECT cat_id ,MAX(shop_price) from goods_l GROUP BY cat_id;
-- 再使用临时表
SELECT goods_l.* from goods_l,(
SELECT cat_id ,MAX(shop_price) as max_good
from goods_l
GROUP BY cat_id
) goods
where goods_l.cat_id= goods.cat_id and shop_price = max_good;
查询结果
关键字 ALL 与 ANY
-- 请思考:如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
-- 请思考:如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
SELECT ename,sal,deptno from emp where sal >ALL(
SELECT sal from emp where deptno = '30');
SELECT ename,sal,deptno from emp where sal >(
SELECT MAX(sal) from emp where deptno = '30');
-- 请思考:如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
-- 请思考:如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
SELECT ename,sal,deptno from emp where sal >ANY(
SELECT sal from emp where deptno = '30');
多列子查询
多列子查序则是指查询返回多个列数据的子查询语句
(字段1,字段2...)=(select 字段1,字段2 from。。。。)
-- 请思考如何查询与smith的部门和岗位完全相同的所有雇员(并且不含smith本人)
#请思考如何查询与smith的部门和岗位完全相同的所有雇员(并且不含smith本人)
-- 先分析 查询smith的部门与岗位
SELECT deptno,job FROM emp WHERE ename = 'SMITH';
SELECT * from emp WHERE (deptno,job) = (
SELECT deptno,job FROM emp
WHERE ename = 'SMITH'
) AND ename != 'SMITH';
子查询练习
# 请思考:如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
SELECT ename,sal,deptno from emp where sal >ALL(
SELECT sal from emp where deptno = '30');
# 请思考:如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
SELECT ename,sal,deptno from emp where sal >ANY(
SELECT sal from emp where deptno = '30');
--
#请思考如何查询与smith的部门和岗位完全相同的所有雇员(并且不含smith本人)
# 先分析 查询smith的部门与岗位
SELECT deptno,job FROM emp WHERE ename = 'SMITH';
SELECT * from emp WHERE (deptno,job) = (
SELECT deptno,job FROM emp
WHERE ename = 'SMITH'
) AND ename != 'SMITH';