sql练习汇总(oracle和sqlserver两个版本的答案)

最近练习sql语句,先把表结构贴来,这几张应该很常见,记得有一家公司笔试题就有这些表和问题,当时刚出来实习,sql根本不会,直接挂掉了。说多都是心酸史呀!

1.建表的SQL

注:下面的sql语句中的类型是oracle数据库类型的。

(1)CREATE TABLE EMP

       (EMPNONUMBER(4) NOT NULL,

        ENAMEVARCHAR2(10),

        JOBVARCHAR2(9),

        MGRNUMBER(4),

       HIREDATE DATE,

        SALNUMBER(7, 2),

        COMMNUMBER(7, 2),

       DEPTNO NUMBER(2));

(2)CREATE TABLE DEPT

      (DEPTNO NUMBER(2),

        DNAMEVARCHAR2(14),

        LOC VARCHAR2(13) );

(3)CREATE TABLE BONUS

       (ENAME VARCHAR2(10),

        JOB   VARCHAR2(9),

        SAL   NUMBER,

        COMM  NUMBER);

(4)CREATE TABLE SALGRADE

       (GRADE NUMBER,

        LOSAL NUMBER,

        HISAL NUMBER);

(5)CREATE TABLE DUMMY

       (DUMMY NUMBER);

 

2.四张表结构和数据

表一:部门表DEPT(使用DESC DEPT;查询)

NO

名称

类型

描述

1

DEPTNO

NUMBER(2)

表示部门编号有两位数字所组成

2

DNAME

VARCHAR2(14)

表示部门名称最多由14个字符所组成

3

LOC

VARCHAR2(13)

表示部门所在位置

 

 





(SELECT* FROM DEPT;)

NO

DEPTNO

DNAME

LOC

1

10

ACCOUNTING(财务部,会计部)

NEWYORK(纽约)

2

20

RESEARCH(调研部)

DALLAS(达拉斯)

3

30

SALES(营业部,市场部)

CHICAGO(芝加哥)

4

40

OPERATIONS(运营部)

BOSTON(波士顿)

 

表二:雇员表EMP(使用DESCEMP;查询)

名称

类型

描述

EMPNO

NUMBER(4)

表示雇员编号,由四个数字组成

ENAME

VARCHAR2(10)

表示雇员姓名,由10个字符组成

JOB

VARCHAR2(9)

表示雇员的职位,由9个字符组成

MGR

NUMBER(4)

表示雇员对应的领导编号,领导也是雇员

HIREDATE

DATE

表示雇员的雇佣日期

SAL

NUMBER(7,2)

表示雇员的基本工资,由两位小数5位整数和2位小数组成,共7位

COMM

NUMBER(7,2)

表示雇员的奖金

DEPTNO

NUMBER(2)

表示雇员所在部门的编号

 

(SELECT* FROM EMP;)

NO

EMPNO

ENAME

JOB

MGR

HIREDATE

SAL

COMM

DEPTNO

1

7369

SMITH(史密斯)

CLERK(办事员)

7902

17-12月-80

800

 

20

2

7499

ALLEN(艾伦)

SALESMAN(销售员)

7698

20-2月-81

1600

300

30

3

7521

WARD

(沃德)

SALESMAN

7698

22-2月-81

1250

500

30

4

7566

JONES

(琼斯)

MANAGER(经理主管)

7839

02-4月-81

2975

 

20

5

7654

MARTIN()马丁

SALESMAN

7698

28-9月-81

1250

1400

30

6

7698

BLAKE

(布雷克)

MANAGER

7839

01-5月-81

2850

 

30

7

7782

CLARK(克拉克)

MANAGER

7839

09-6月-81

2450

 

10

8

7788

SCOTT(斯科特)

ANALYST(分析员)

7566

19-4月-87

3000

 

20

9

7839

KING(金)

PRESIDENT(总经理,总裁)

 

17-11月-81

5000

 

10

10

7844

TURNER(特纳)

SALESMAN

7698

08-9月-81

1500

0

30

11

7876

ADANS(奥丹斯)

CLERK

7788

23-5月-87

1100

 

20

12

7900

JAMES(詹姆斯)

CLERK

7698

03-12月-81

950

 

30

13

7902

FORD(福特)

ANALYST

7566

03-12月-81

3000

 

20

14

7934

MILLER(米勒)

CLERK

7782

23-1月-82

1300

 

10

 

表三:工资等级表:(DESC SALGRADE)

NO

名称

类型

描述

1

GRADE

NUMBER

工资的等级

2

LOSAL

NUMBER

此等级的最低工资

3

HISAL

NUMBER

此等级的最高工资

 

(SELECT* FROM SALGRADE;查询)

NO

GRADE

LOSAL

HISAL

1

1

700

1200

2

2

1201

1400

3

3

1401

2000

4

4

2001

3000

5

5

3001

9999

 

 

表四:工资表BONUS:(DESCBONUS)

NO

名称

类型

描述

1

ENAME

VARCHAR2(10)

雇员姓名

2

JOB

VARCHAR2(9)

雇员职位

3

SAL

NUMBER

雇员基本工资

4

COMM

NUMBER

奖金,提成

 

3.练习题

注:20道题,都是写出对应的sql,每道题中的答案中:

(1)是我下载前别人给的答案(用oracle函数),(2)是我写的(sqlsever函数)。

我用vs10自带的sqlserver2008,有些不爽,运行sql语句,它会把你写的sql语句修改成它的模板;有的可能没有(2),因为是通用的或者我还没想到用另一种写出来,有的下面会有些注解,新手练习,相互学习。(1)和(2)的sql可能有问题,请指正。本人菜鸟一枚,如果你有好的答案或者sql写错了,请留言,我会完善sql.谢谢!

--1.列出至少有一个员工的所有部门

(1)select d.dname,t1.co

from (select e.deptno,count(e.deptno) co from emp e group by e.deptno) t1,

dept d

where d.deptno =t1.deptnod

and t1.co > 1;

(2) SELECT    e.DEPTNO, d.DNAME, d.LOC,COUNT(*) AS 总人数

FROM        EMPAS e LEFT OUTER JOIN  DEPT AS d ON e.DEPTNO= d.DEPTNO

GROUP BY    e.DEPTNO,d.DNAME, d.LOC

HAVING      (COUNT(*) >= 1)

--2.列出薪金比‘SMITH’多的所有员工

select *

from emp

where sal > (selecte.sal from emp e where e.ename = 'SMITH');

--3.列出所有员工的姓名以及直接上级的姓名

(1)select e1.ename,e2.ename from emp e1, emp e2 where e1.mgr = e2.empno;

(2)SELECT    e1.EMPNO,e1.ENAME, e2.EMPNO AS 上级工号,e2.ENAME AS 上级姓名

FROM    EMP AS e1 LEFT OUTER JOIN    EMP AS e2 ON e1.MGR = e2.EMPNO

注:(1)中sql会漏掉没有上级的员工信息

--4.列出受雇日期早于直接上级入职日期的职工编号,姓名,部门名称

(1)select e1.empno 员工号,

e1.ename 员工姓名,

e1.hiredate 入职日期,

e2.ename 上级姓名,

e2.hiredate 上级入职日期

from emp e1, empsaj

where e1.mgr =e2.empno

and e1.hiredate <e2.hiredate;

(2)SELECT   e1.EMPNO, e1.ENAME, e1.DEPTNO,t.DNAME, e1.HIREDATE, e2.EMPNO AS 上级工号, e2.ENAME AS 上级姓名, e2.HIREDATE AS 上级雇佣日期

FROM   EMP ASe1 LEFT OUTER JOIN   EMP AS e2 ON e1.MGR= e2.EMPNO INNER   JOIN DEPT AS t ON e1.DEPTNO= t.DEPTNO

WHERE  (e1.HIREDATE< e2.HIREDATE)

注:(2)中sql是被编译处理后的sql

--5.列出部门名称和这些部门的员工信息,同时列出没有员工的部门信息

注:(部门表 左连接 员工表)或者 (员工表右连接 部门表)

(1)select d.dname, e.*

from emp e

right outer join deptd

on e.deptno = d.deptno

order by d.dname;

(2)SELECT  d.DNAME,e.EMPNO, e.ENAME, e.JOB, e.MGR, e.HIREDATE, e.SAL, e.COMM, e.DEPTNO

FROM  DEPT AS d LEFT OUTER JOIN    EMP AS e ON d.DEPTNO = e.DEPTNO

注:(1)是(员工表 右连接 部门表) (2)(部门表 左连接 员工表)

--6.列出所有职位为'CLERK'的姓名 和部门名称,部门人数

(1)

select e.ename,d.dname

from emp e, dept d

where e.deptno =d.deptno

and e.job = 'CLERK';

(2)SELECT          d.DEPTNO, d.DNAME, d.LOC, COUNT(*) AS'SUM'

FROM     DEPT AS d LEFT OUTER JOIN   EMP AS e ON d.DEPTNO = e.DEPTNO

WHERE    (d.DEPTNO IN

                 (SELECT          DEPTNO

                  FROM               EMP AS e

                  WHERE           (JOB = 'CLERK')))

GROUP BY  d.DEPTNO, d.DNAME, d.LOC

注:(1)的sql存在问题:没有计算部门人数

 --7.列出最低工薪大于1500的各种工作以及从事此工作的全部雇员的人数

select distinct e.job,count(*)

from emp e

where e.sal > 1500

group by e.job;

注:先决条件是的工薪大于1500

--8.列出在部门'SALES'(销售部)工作的员工信息,假设不知道销售部门的部门c

(1)select e.ename from emp e where e.job = 'SALESMAN';

(2)select *  from emp  where deptno= (select deptno  from dept where DNAME='SALES');

注:(1)错误:部门为'SALES',不是job

--9.列出薪金高于公司平均薪金的所有员工,部门,上级领导,工资级别

select e2.ename, e2.deptno,e3.ename, s.grade

from emp e2, emp e3,salgrade s

where e2.sal >(select avg(e.sal) from emp e)

and (e2.sal betweens.losal and s.hisal)

and e2.mgr = e3.empno;

--10.列出与'SCOTT'从事相同工作的所有员工及部门名称

select e.ename,d.dname

from emp e, dept d

where e.job in (selecte2.job from emp e2 where e2.ename = 'SCOTT')

and e.deptno =d.deptno;

注:为什么用in 不用 =,如果有 >=2 个人的名字为'SCOTT', 用=就出错。

--11.列出薪金等于部门20中的员工的薪金的所有员工和薪金

select *

from emp

where sal in (selecte.sal from emp e where e.deptno = 20);

注:用in而不是=

--12.列出薪金高于部门30中的员工的薪金的所有员工和薪金,部门名称

select e2.ename,e2.sal, d.dname

from emp e2, dept d

where sal >

(select max(t1.sal)

from (select e.salfrom emp e where e.deptno = 30) t1)

and d.deptno =e2.deptno;

注: 薪金高于部门30中的员工的薪金,思路:找到部门30最高的的薪金,然后查找比这个薪金高的员工资料。

--13.列出每个部门员工的数量,平均工资和平均年限

(1)select t2.*, t1.ro3 平均年限

from (select e2.deptno,count(*) 员工数量, avg(e2.sal) 平均工资

from emp e2

group by e2.deptno)t2,

(select ro2.deptno,avg(ro2.ro) ro3

from (selecte3.deptno,

round(months_between(sysdate,e3.hiredate) / 12) ro

from emp e3) ro2

group by ro2.deptno)t1

where t1.deptno =t2.deptno;

(2)SELECT   e.DEPTNO, d.DNAME, COUNT(*) AS '总人数', AVG(e.SAL) AS '平均薪金', AVG(DATEDIFF(year, e.HIREDATE,GETDATE()))  AS '平均年限'

FROM      EMPAS e INNER JOIN   DEPT AS d ON e.DEPTNO =d.DEPTNO

GROUP BY   e.DEPTNO, d.DNAME

注:在Sqlserver中: datediff(day/year…,起始日期,结束日期)函数,计算两个时间的间隔,(2)的sql只适用用于SqlServer.

--14.列出所有员工的姓名,工资,部门名称

select e.ename, e.sal,d.dname

from emp e, dept d

where d.deptno =e.deptno;

--15.列出所有部门信息和部门人数

(1)select d.*, nvl(t1.c, 0)部门人数

from dept d

left outer join(select e.deptno, count(e.deptno) c

from emp e

group by e.deptno) t1

on d.deptno =t1.deptno;

(2)

SELECT         e.DEPTNO, d.DNAME, COUNT(*) AS '总人数'

FROM       DEPT AS d LEFT OUTER JOIN    EMPAS e ON d.DEPTNO = e.DEPTNO

GROUP BY   e.DEPTNO, d.DNAME

(3)SELECT     d.DEPTNO,d.DNAME, d.LOC, ISNULL(t1.c, 0) AS 部门人数

FROM       DEPT AS d LEFT OUTER JOIN

    (SELECT          DEPTNO,COUNT(DEPTNO) AS c

                                  FROM               EMP AS e

                                  GROUP BY    DEPTNO) AS t1 ON d.DEPTNO = t1.DEPTNO

注:(1)中NVl()函数,如果第一个参数不为null,返回它,如果为null,返回第二参数(其实就是NULL给他一个默认值);oracle函数。提醒一点:NULL这个值表示UNKNOWN(未知):它不表示“”(空字符串)。

(3)中ISNULL和oracle中NVl()相同的作用,是sqlserver函数。

(2)是有问题的:

如果有个部门没有员工,

一、查出的结果对应的DEPTNO为null;

二、总人数为1,(不要惊讶,因为用的count函数,两个表连接后查询有一行的数据的,但是只是有的值为null,);

有人会说:e.DEPTNO修改为  d.DEPTNO(group by 后面那个也修改),这个只能解决上面提到的第一个问题(查出的结果对应的DEPTNO为null),但是第二个还是没有解决。

--16.列出各种工作的最低工薪以及从事此工作的员工信息

(1)select *

from emp, (select e.jobj, min(e.sal) s from emp e group by e.job) t1

where emp.job = t1.j

and emp.sal = t1.s;

(2) SELECT          e.EMPNO, e.ENAME, e.JOB, e.MGR,e.HIREDATE, e.SAL, e.COMM, e.DEPTNO, c.sal1, c.JOB AS Expr1

FROM    EMPAS e INNER JOIN

                                (SELECT          MIN(SAL) AS sal1, JOB

                                  FROM               EMP

                                  GROUP BY    JOB) AS c ON e.JOB = c.JOB AND e.SAL =c.sal1

--17.列出各个部门职位为'MANAGER'(经理)的最低工薪

select a.dname,min(a.sal)

from (select d.dname,e.sal

from emp e, dept d

where e.deptno = d.deptno

and e.job = 'MANAGER')a

group by a.dname;

(2)SELECT  EMPNO, ENAME,DEPTNO, MIN(SAL) AS sal

FROM     EMP

WHERE   (JOB = 'MANAGER')

GROUP BY   ENAME, DEPTNO, EMPNO

--18.列出所有员工的年薪,按照年薪由低到高排序

select e.ename, e.sal* 12 from emp e order by e.sal;

--19.查出每个员工的上级领导,并且求出这些主管的工资超过3000

select e1.ename 本人姓名, e2.ename 领导姓名, e2.sal 领导工资

from emp e1, emp e2

where e1.mgr =e2.empno

and e2.sal > 3000;

--20.求出部门名称中带有'S'的部门员工的工资合计,部门人数

select d.dname 部门名称, t2.su 工资合计, t2.co 部门人数

from (select e.deptno,sum(e.sal) su, count(e.empno) co

from emp e

group by e.deptno) t2,

dept d

where t2.deptno in(select d.deptno from dept d where d.dname like '%S%')

and d.deptno =t2.deptno;

(2)SELECT  d.DEPTNO, d.DNAME, ISNULL(e.count,0) AS 部门人数, ISNULL(e.sum,0) AS 工资合计

FROM  DEPT AS d LEFT OUTER JOIN     (SELECT          DEPTNO, COUNT(*) AS count, SUM(SAL)AS sum

FROM        EMP

GROUP BY    DEPTNO) AS e ON d.DEPTNO = e.DEPTNO

WHERE      (d.DNAMELIKE '%S%')

注:前面解释过NVL()和ISnull()两个函数的用法(问题15的答案注解中)

4.总结

        以上的练习题只是初级的,学会一些基本的用法,还有一些基本的sql知识我会后续慢慢写出来,比如oracle和sqlserver基本函数,sql语句的优化,列转行等。

借用前辈们的一句话:“SQL开发是一门语言,它很容易学,但是很难掌握”,我感觉说得很有道理,我实习前不是很注重sql的学习,当出去进行几次面试时才意识到这个东西还是很重要的,找实习工作时有个考官问了我这样一个问题:select语句的执行顺序。我当时就懵了,这个问题的答案网上一大堆,有兴趣的话可以百度一下。

 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值