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. 请用 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. 作 者 : 不 详 发 文 时 间 : 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. 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. 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)
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. /
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. 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. 去年应聘一个职位未果,其间被考了一个看似简单的题,但我没有找到好的大案.
不知各位大虾有无好的解法?
题为:
有两个表, 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. 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. 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. 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. 额
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. 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. 有 表 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