Sql 常见面试题(总结)

1.用一条 SQL 语句 查询出每门课都大于 80 分的学生姓名



name                     kecheng                          fenshu

张    ...
请用 SQL 语句实现:从 TestDB 数据表中查询出所有月份的发生额都比 101 科目相应月份的
发 生 额 高 的 科 目 。 请 注 意 : TestDB 中 有 很 多 科 目 , 都 有 1 - 12 月 份 的 发 生 额 。
A...
作      者    :       不       详            发      文            时      间         :       2003.05.29           10:55:05

说 明 :...
WHERE     TO_CHAR(UPD_DATE,'YYYY/MM')       =       TO_CHAR(SYSDATE,           'YYYY/MM'))         X,

(SELECT            ...
SUM(decode(TO_CHAR(a.telfeedate,               'mm'),       '06',     a.factration))         AS       JUE,

SUM(decode(TO_...
where b.id     in(select    b.id from     b,a   where    b.key=a.key);
***************************************************...
SQL>           select           courseid,           coursename           ,score
,decode(sign(score-60),-1,'fail','pass')  ...
/
create or replace function merge (pv in strings_table) return varchar2
is
ls                             varchar2(4000);...
5          order          by           e.ename)           ||',            '||
6       lead(e.ename,2)        over        (...
去年应聘一个职位未果,其间被考了一个看似简单的题,但我没有找到好的大案.
不知各位大虾有无好的解法?



题为:
有两个表, t1, t2,
Table t1:

SELLER | NON_SELLER
----- -----

A   B
...
A   9 900
B   9 800
C   9 700
D   9 600
A   9.5 20
B   9.5 100
C   9.5 120
D   9.5 120
A   10 0
B   10 80
C   10 80
D   10...
select    *    from    table2    order     by    outdate,convert(int,username)

2.         组          合           查       ...
order                        by                   outdate,convert(int,username)
返        回        结          果      100*10...
额
outdate                                                       username    cash
2001-10-01    00:00:00.000               ...
CROSS                                   join
(
select         distinct          username          from          table2
)  ...
有 表 a 存 储 二 叉 树 的 节 点 , 要 用 一 条 sql 语 句 查 出 所 有 节 点 及 节 点 所 在 的 层 .
表                                 a
c1             c2 ...
N                   3
F                   4
I                   4
K                   4

已   选   择   9   行   。
Upcoming SlideShare
Loading in …5
×

Sql常见面试题

2,059 views
1,987 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,059
On SlideShare
0
From Embeds
0
Number of Embeds
20
Actions
Shares
0
Downloads
15
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Sql常见面试题

  1. 1. Sql 常见面试题(总结) 1.用一条 SQL 语句 查询出每门课都大于 80 分的学生姓名 name kecheng fenshu 张 三 语 文 81 张 三 数 学 75 李 四 语 文 76 李 四 数 学 90 王 五 语 文 81 王 五 数 学 100 王 五 英 语 90 A: select distinct name from table where name not in (select distinct name from table where fenshu<=80) 2. 学 生 表 如 下 : 自 动 编 号 学 号 姓 名 课 程 编 号 课 程 名 称 分 数 1 2005001 张 三 0001 数 学 69 2 2005002 李 四 0001 数 学 89 3 2005001 张 三 0001 数 学 69 删 除 除 了 自 动 编 号 不 同 , 其 他 都 相 同 的 学 生 冗 余 信 息 A: delete tablename where 自动编号 not in(select min(自动编号) from tablename group by 学号,姓名,课程编号,课程名称,分数) 一个叫 department 的表,里面只有一个字段 name,一共有 4 条纪录,分别是 a,b,c,d,对应 四 个 球 对 , 现 在 四 个 球 对 进 行 比 赛 , 用 一 条 sql 语 句 显 示 所 有 可 能 的 比 赛 组 合 . 你先按你自己的想法做一下,看结果有我的这个简单吗? 答 : select a.name, b.name from team a, team b where a.name < b.name
  2. 2. 请用 SQL 语句实现:从 TestDB 数据表中查询出所有月份的发生额都比 101 科目相应月份的 发 生 额 高 的 科 目 。 请 注 意 : TestDB 中 有 很 多 科 目 , 都 有 1 - 12 月 份 的 发 生 额 。 AccID : 科 目 代 码 , Occmonth : 发 生 额 月 份 , DebitOccur : 发 生 额 。 数据库名:JcyAudit,数据集:Select * from TestDB 答 : select a.* from TestDB a ,(select Occmonth,max(DebitOccur) Debit101ccur from TestDB where AccID='101' group by Occmonth) b where a.Occmonth=b.Occmonth and a.DebitOccur>b.Debit101ccur ******************************************************************************* ***** 面 试 题 : 怎 么 把 这 样 一 个 表 儿 year month amount 1991 1 1.1 1991 2 1.2 1991 3 1.3 1991 4 1.4 1992 1 2.1 1992 2 2.2 1992 3 2.3 1992 4 2.4 查 成 这 样 一 个 结 果 year m1 m2 m3 m4 1991 1.1 1.2 1.3 1.4 1992 2.1 2.2 2.3 2.4 答 案 一 、 select year, (select amount from aaa m where month=1 and m.year=aaa.year) as m1, (select amount from aaa m where month=2 and m.year=aaa.year) as m2, (select amount from aaa m where month=3 and m.year=aaa.year) as m3, (select amount from aaa m where month=4 and m.year=aaa.year) as m4 from aaa group by year 这 个 是 ORACLE 中 做 的 : select * from (select name, year b1, lead(year) over (partition by name order by year) b2, lead(m,2) over(partition by name order by year) b3,rank()over( partition by name order by year) rk from t) where rk=1; ******************************************************************************* ***** 精 妙 的 SQL 语 句 ! 精 妙 SQL 语 句
  3. 3. 作 者 : 不 详 发 文 时 间 : 2003.05.29 10:55:05 说 明 : 复 制 表 ( 只 复 制 结 构 , 源 表 名 : a 新 表 名 : b) SQL: select * into b from a where 1<>1 说 明 : 拷 贝 表 ( 拷 贝 数 据 , 源 表 名 : a 目 标 表 名 : b) SQL: insert into b(a, b, c) select d,e,f from b; 说 明 : 显 示 文 章 、 提 交 人 和 最 后 回 复 时 间 SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b 说 明 : 外 连 接 查 询 ( 表 名 1 : a 表 名 2 : b) SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c 说 明 : 日 程 安 排 提 前 五 分 钟 提 醒 SQL: select * from 日 程 安 排 where datediff('minute',f 开 始 时 间 ,getdate())>5 说 明 : 两 张 关 联 表 , 删 除 主 表 中 已 经 在 副 表 中 没 有 的 信 息 SQL: delete from info where not exists ( select * from infobz where info.infid=infobz.infid ) 说 明 : -- SQL: SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE FROM TABLE1, (SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND FROM TABLE2
  4. 4. WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X, (SELECT NUM, UPD_DATE, STOCK_ONHAND FROM TABLE2 WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, 'YYYY/MM') ¦¦ '/01','YYYY/MM/DD') - 1, 'YYYY/MM') ) Y, WHERE X.NUM = Y.NUM ( + ) AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <> X.STOCK_ONHAND ) B WHERE A.NUM = B.NUM 说 明 : -- SQL: select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and 系 名 称 ='"&strdepartmentname&"' and 专 业 名 称 ='"&strprofessionname&"' order by 性 别 , 生 源 地 , 高 考 总 成 绩 说 明 : 从数据库中去一年的各单位电话费统计(电话费定额贺电化肥清单两个表来源) SQL: SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') AS telyear, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '01', a.factration)) AS JAN, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY,
  5. 5. SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV, SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration FROM TELFEESTAND a, TELFEE b WHERE a.tel = b.telfax) a GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') 说 明 : 四 表 联 查 问 题 : SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where ..... 说 明 : 得 到 表 中 最 小 的 未 使 用 的 ID 号 SQL: SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID FROM Handle WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a) ******************************************************************************* 有两个表 A 和 B,均有 key 和 value 两个字段,如果 B 的 key 在 A 中也有,就把 B 的 value 换 为 A 中 对 应 的 value 这道题的 SQL 语句怎么写? update b set b.value=(select a.value from a where a.key=b.key)
  6. 6. where b.id in(select b.id from b,a where b.key=a.key); *************************************************************************** 高级 sql 面试题 原 表 : courseid coursename score ------------------------------------- 1 java 70 2 oracle 90 3 xml 40 4 jsp 30 5 servlet 80 ------------------------------------- 为 了 便 于 阅 读 , 查 询 此 表 后 的 结 果 显 式 如 下 ( 及 格 分 数 为 60): courseid coursename score mark --------------------------------------------------- 1 java 70 pass 2 oracle 90 pass 3 xml 40 fail 4 jsp 30 fail 5 servlet 80 pass --------------------------------------------------- 写出此查询语句 没 有 装 O R A C L E , 没 试 过 select courseid, coursename ,score ,decode(sign(score-60),-1,'fail','pass') as mark from course 完 全 正 确 SQL> desc course_v Name Null? Type ----------------------------------------- -------- ---------------------------- COURSEID NUMBER COURSENAME VARCHAR2(10) SCORE NUMBER SQL> select * from course_v; COURSEID COURSENAME SCORE ---------- ---------- ---------- 1 java 70 2 oracle 90 3 xml 40 4 jsp 30 5 servlet 80
  7. 7. SQL> select courseid, coursename ,score ,decode(sign(score-60),-1,'fail','pass') as mark from course_v; COURSEID COURSENAME SCORE MARK ---------- ---------- ---------- ---- 1 java 70 pass 2 oracle 90 pass 3 xml 40 fail 4 jsp 30 fail 5 servlet 80 pass ******************************************************************************* 原 表 : id proid proname 1 1 M 1 2 F 2 1 N 2 2 G 3 1 B 3 2 A 查 询 后 的 表 : id pro1 pro2 1 M F 2 N G 3 B A 写出查询语句 解 决 方 案 sql 求 解 表 a 列 a1 a2 记 录 1 a 1 b 2 x 2 y 2 z 用 select 能 选 成 以 下 结 果 吗 ? 1 ab 2 xyz 使用 pl/sql 代码实现,但要求你组合后的长度不能超出 oracle varchar2 长度的限制。 下 面 是 一 个 例 子 create or replace type strings_table is table of varchar2(20);
  8. 8. / create or replace function merge (pv in strings_table) return varchar2 is ls varchar2(4000); begin for i in 1..pv.count loop ls := ls || pv(i); end loop; return ls; end; / create table t (id number,name varchar2(10)); insert into t values(1,'Joan'); insert into t values(1,'Jack'); insert into t values(1,'Tom'); insert into t values(2,'Rose'); insert into t values(2,'Jenny'); column names format a80; select t0.id,merge(cast(multiset(select name from t where t.id = t0.id) as strings_table)) names from (select distinct id from t) t0; drop type strings_table; drop function merge; drop table t; 用 sql : Well if you have a thoretical maximum, which I would assume you would given the legibility of listing hundreds of employees in the way you describe then yes. But the SQL needs to use the LAG function for each employee, hence a hundred emps a hundred LAGs, so kind of bulky. This example uses a max of 6, and would need more cut n pasting to do more than that. SQL> select deptno, dname, emps 2 from ( 3 select d.deptno, d.dname, rtrim(e.ename ||', '|| 4 lead(e.ename,1) over (partition by d.deptno
  9. 9. 5 order by e.ename) ||', '|| 6 lead(e.ename,2) over (partition by d.deptno 7 order by e.ename) ||', '|| 8 lead(e.ename,3) over (partition by d.deptno 9 order by e.ename) ||', '|| 10 lead(e.ename,4) over (partition by d.deptno 11 order by e.ename) ||', '|| 12 lead(e.ename,5) over (partition by d.deptno 13 order by e.ename),', ') emps, 14 row_number () over (partition by d.deptno 15 order by e.ename) x 16 from emp e, dept d 17 where d.deptno = e.deptno 18 ) 19 where x = 1 20 / DEPTNO DNAME EMPS ------- ----------- ------------------------------------------ 10 ACCOUNTING CLARK, KING, MILLER 20 RESEARCH ADAMS, FORD, JONES, ROONEY, SCOTT, SMITH 30 SALES ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD also 先 create function get_a2; create or replace function get_a2( tmp_a1 number) return varchar2 is Col_a2 varchar2(4000); begin Col_a2:=''; for cur in (select a2 from unite_a where a1=tmp_a1) loop Col_a2=Col_a2||cur.a2; end loop; return Col_a2; end get_a2; select distinct a1 ,get_a2(a1) from unite_a 1 ABC 2 EFG 3 KMN ******************************************************************************* 一个 SQL 面试题
  10. 10. 去年应聘一个职位未果,其间被考了一个看似简单的题,但我没有找到好的大案. 不知各位大虾有无好的解法? 题为: 有两个表, t1, t2, Table t1: SELLER | NON_SELLER ----- ----- A B A C A D B A B C B D C A C B C D D A D B D C Table t2: SELLER | COUPON | BAL ----- --------- --------- A 9 100 B 9 200 C 9 300 D 9 400 A 9.5 100 B 9.5 20 A 10 80 要求用 SELECT 语句列出如下结果:------如 A 的 SUM(BAL)为 B,C,D 的和,B 的 SUM(BAL)为 A,C,D 的和....... 且用的方法不要增加数据库负担,如用临时表等. NON-SELLER| COUPON | SUM(BAL) ------- --------
  11. 11. A 9 900 B 9 800 C 9 700 D 9 600 A 9.5 20 B 9.5 100 C 9.5 120 D 9.5 120 A 10 0 B 10 80 C 10 80 D 10 80 关于论坛上那个 SQL 微软面试题 问 题 : 一百个账户各有 100$,某个账户某天如有支出则添加一条新记录,记录其余额。一百天后 , 请 输 出 每 天 所 有 账 户 的 余 额 信 息 这个问题的难点在于每个用户在某天可能有多条纪录,也可能一条纪录也没有(不包括第 一 天 ) 返 回 的 记 录 集 是 一 个 100 天 *100 个 用 户 的 纪 录 集 下 面 是 我 的 思 路 : 1. 创 建 表 并 插 入 测 试 数 据 : 我 们 要 求 username 从 1-100 CREATE TABLE [dbo].[TABLE2] ( [username] [varchar] (50) NOT NULL , -- 用 户 名 [outdate] [datetime] NOT NULL , -- 日 期 [cash] [float] NOT NULL -- 余 额 ) ON [PRIMARY declare @i int set @i=1 while @i<=100 begin insert table2 values(convert(varchar(50),@i),'2001-10-1',100) insert table2 values(convert(varchar(50),@i),'2001-11-1',50) set @i=@i+1 end insert table2 values(convert(varchar(50),@i),'2001-10-1',90)
  12. 12. select * from table2 order by outdate,convert(int,username) 2. 组 合 查 询 语 句 : a. 我 们 必 须 返 回 一 个 从 第 一 天 开 始 到 100 天 的 纪 录 集 : 如 : 2001-10-1 ( 这 个 日 期 是 任 意 的 ) 到 2002-1-8 由 于 第 一 天 是 任 意 一 天 , 所 以 我 们 需 要 下 面 的 SQL 语 句 : select top 100 dateadd(d,convert(int,username)-1,min(outdate)) as outdate from table2 group by username order by convert(int,username) 这 里 的 奥 妙 在 于 : convert(int,username)-1 ( 记 得 我 们 指 定 用 户 名 从 1-100 :-)) group by username,min(outdate): 第 一 天 就 可 能 每 个 用 户 有 多 个 纪 录 。 返 回 的 结 果 : outdate ------------------------------------------------------ 2001-10-01 00:00:00.000 ......... 2002-01-08 00:00:00.000 b. 返 回 一 个 所 有 用 户 名 的 纪 录 集 : select distinct username from table2 返 回 结 果 : username -------------------------------------------------- 1 10 100 ...... 99 c. 返 回 一 个 100 天 记 录 集 和 100 个 用 户 记 录 集 的 笛 卡 尔 集 合 : select * from ( select top 100 dateadd(d,convert(int,username)-1,min(outdate)) as outdate from table2 group by username order by convert(int,username) ) as A CROSS join ( select distinct username from table2 ) as B
  13. 13. order by outdate,convert(int,username) 返 回 结 果 100*100 条 纪 录 : outdate username 2001-10-01 00:00:00.000 1 ...... 2002-01-08 00:00:00.000 100 d. 返 回 当 前 所 有 用 户 在 数 据 库 的 有 的 纪 录 : select outdate,username,min(cash) as cash from table2 group by outdate,username order by outdate,convert(int,username) 返 回 纪 录 : outdate username cash 2001-10-01 00:00:00.000 1 90 ...... 2002-01-08 00:00:00.000 100 50 e. 将 c 中 返 回 的 笛 卡 尔 集 和 d 中 返 回 的 纪 录 做 left join: select C.outdate,C.username, D.cash from ( select * from ( select top 100 dateadd(d,convert(int,username)-1,min(outdate)) as outdate from table2 group by username order by convert(int,username) ) as A CROSS join ( select distinct username from table2 ) as B ) as C left join ( select outdate,username,min(cash) as cash from table2 group by outdate,username ) as D on(C.username=D.username and datediff(d,C.outdate,D.outdate)=0) order by C.outdate,convert(int,C.username) 注意:用户在当天如果没有纪录,cash 字段返回 NULL,否则 cash 返回每个用户当天的余
  14. 14. 额 outdate username cash 2001-10-01 00:00:00.000 1 90 2001-10-01 00:00:00.000 2 100 ...... 2001-10-02 00:00:00.000 1 90 2001-10-02 00:00:00.000 2 NULL <-- 注 意 这 里 ...... 2002-01-08 00:00:00.000 100 50 f.好了,现在我们最后要做的就是,如果 cash 为 NULL,我们要返回小于当前纪录日期的 第一个用户余额(由于我们使用 order by cash,所以返回 top 1 纪录即可,使用 min 应该也 可 以 ) , 这 个 余 额 即 为 当 前 的 余 额 : case isnull(D.cash,0) when 0 then ( select top 1 cash from table2 where table2.username=C.username and datediff(d,C.outdate,table2.outdate)<0 order by table2.cash ) else D.cash end as cash g. 最 后 组 合 的 完 整 语 句 就 是 select C.outdate,C.username, case isnull(D.cash,0) when 0 then ( select top 1 cash from table2 where table2.username=C.username and datediff(d,C.outdate,table2.outdate)<0 order by table2.cash ) else D.cash end as cash from ( select * from ( select top 100 dateadd(d,convert(int,username)-1,min(outdate)) as outdate from table2 group by username order by convert(int,username) ) as A
  15. 15. CROSS join ( select distinct username from table2 ) as B ) as C left join ( select outdate,username,min(cash) as cash from table2 group by outdate,username ) as D on(C.username=D.username and datediff(d,C.outdate,D.outdate)=0) order by C.outdate,convert(int,C.username) 返 回 结 果 : outdate username cash 2001-10-01 00:00:00.000 1 90 2001-10-01 00:00:00.000 2 100 ...... 2002-01-08 00:00:00.000 100 50 ******************************************************************************* **** 取出 sql 表中第 31 到 40 的记录(以自动增长 ID 为主键) * 从 数 据 表 中 取 出 第 n 条 到 第 m 条 的 记 录 */ declare @m int declare @n int declare @sql varchar(800) set @m=40 set @n=31 set @sql='select top '+str(@m-@n+1) + '* from idetail where autoid not in( select top '+ str(@n-1) + 'autoid from idetail)' exec(@sql) select top 10 * from t where id not in (select top 30 id from t order by id ) orde by id ------------------------------------------------------------------------------- - select top 10 * from t where id in (select top 40 id from t order by id) order by id desc ******************************************************************************* 一 道 面 试 题 , 写 sql 语 句
  16. 16. 有 表 a 存 储 二 叉 树 的 节 点 , 要 用 一 条 sql 语 句 查 出 所 有 节 点 及 节 点 所 在 的 层 . 表 a c1 c2 A ----------1 ---- ---- / A B B C --------2 A C / / B D D N E ------3 C E / D F F K I ---4 E I D K C N 所 要 得 到 的 结 果 如 下 jd cs ----- ---- A 1 B 2 C 2 D 3 N 3 E 3 F 4 K 4 I 4 有高手指导一下,我只能用 pl/sql 写出来,请教用一条 sql 语句的写法 SQL> select c2, level + 1 lv 2 from test start 3 with c1 = 'A' 4 connect by c1 = prior c2 5 union 6 select 'A', 1 from dual 7 order by lv; C2 LV -- ---------- A 1 B 2 C 2 D 3 E 3
  17. 17. N 3 F 4 I 4 K 4 已 选 择 9 行 。

×