sql 笔试题

个SQL 面试题

去年应聘一个职位未果,其间被考了一个看似简单的题,但我没有找到好的大案.
不知各位大虾有无好的解法?


题为:
有两个表, 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) ------- --------
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)

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
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返回每个用户当天的余额
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
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语句

有表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
N 3
F 4

I 4
K 4

已选择9行。
请教一道SQL面试题!!!

table_a:
id        name        val
1        aaa        30
2        aaa        40
3        aaa        50
1        bbb        35
2        bbb        45
3        bbb        55
table_b:
name        val1        val2        val3
aaa        30        40        50
bbb        35        45        55

请用一个SQL语句实现table_a到table_b的转化。
select *
from (
    select lag(val, 1) over (
                    partition by name
                    order by id
           ) pre,
           val,
           lead(val, 1) over(
                     partition by name
                     order by id
           ) post
    from table_a
) ir
where pre is not null and post is not null;

刚刚查了一下lead和lag的用法,发现即使有4个及以上值亦可采用改变offset参数来实现,如四个值的时候可以:
select * from (
  select name,
    lag(val, 3) over(partition by name order by id) val1,
    lag(val, 2) over(partition by name order by id) val2,
    lag(val, 1) over(partition by name order by id) val3,
    val val4
  from table_a
) where val1 is not null and val2 is not null and val4 is not null;
但子查询的产生的垃圾数据会是最终结果的n-1倍,有没有不用子查询能得到结果的方法呢?求教!
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页