作者:Tony Lu 来源:博客园   酷勤网收集 2008-06-29

摘要
  第二题就比较麻烦了,题目:他们公司网站上的广告位是轮播的,每天某一广告位最多可轮播的广告数量是有限制的,比如A广告位,每天只能轮播三个广告,但销售人员在销售广告位时并不考虑此限制,要求查询出合同表中,超过广告位轮播数量的合同…

    前两天收到一家知名互联网公司的offer(具体哪家公司就不说了^_^),是去做公司内部的MIS系统,使用AspJava语言,虽然本人对ASP比较熟,但最近两年一直在做.NET,本来是不想去的,后来想想还是去看看吧。

      打电话通知面试的时候就已说明,要求上机做两道Sql Server面试题。

第一题比较简单,查询出销售表中,销售额大于本地区平均水平的记录,用一条sql语句就搞定了。

Sales

OrderID

Region

Total

1

A

100.00

2

C

80.00

3

A

130.00

4

B

90.00

5

B

100.00

6

C

120.00

7

A

90.00

8

C

90.00

9

B

80.00

Sql语句:select * from sales as s inner join (select avg(total) as avge,region from sales group by region) avgtable on s.region = avgtable.region where total > avgtable.avge 

第二题就比较麻烦了,他们公司网站上的广告位是轮播的,每天某一广告位最多可轮播的广告数量是有限制的,比如A广告位,每天只能轮播三个广告,但销售人员在销售广告位时并不考虑此限制,要求查询出合同表中,超过广告位轮播数量的合同。

合同表 Orders

OrderID

Positioncode

Startdate

Enddate

1

A

2006-11-01

2006-11-03

2

C

2006-11-02

2006-11-03

3

B

2006-11-01

2006-11-04

4

A

2006-11-03

2006-11-04

5

C

2006-11-01

2006-11-02

6

B

2006-11-02

2006-11-05

7

A

2006-11-02

2006-11-03

8

A

2006-11-04

2006-11-05

9

C

2006-11-03

2006-11-04

10

C

2006-11-02

2006-11-04

广告位表 Product

Positioncode

Showcount

A

2

B

1

C

3

说明:对于广告位A来讲,轮播情况如下表

OrderID

2006-11-01

2006-11-02

2006-11-03

2006-11-04

2006-11-05

1

         

4

         

7

         

8

         

广告位A每天最多可轮播2个广告,但合同表中2006-11-03这天有三个广告(147),对于广告位A,1、4、7则是最终需要得到的结果。如需要可使用临时表、存储过程等。

可能当时也有点紧张吧,这道题面试的时候弄了两个多小时,还是没有解决,最终只好放弃了。不过还是不死心,回家后又仔细研究了一下,终于给解决了,使用了存储过程,但不知道还有没有更好的方式,过程过下。
    
create proc overcontract
    as
    declare @mindate smalldatetime
    declare @days int
    declare @temptable table ( orderid int)

set @mindate = (select min(startdate) from orders)
    set @days = (select datediff(d,min(startdate),max(enddate)) from orders)

while (@days>-1)
       begin
              declare @curdate smalldatetime
              set @curdate = dateadd(d,@days,@mindate) 

              insert into @temptable select o.orderid from product as p inner join
 (select count(positioncode) as total,positioncode from orders where @curdate between startdate and enddate group by positioncode ) dt on dt.positioncode = p.positioncode left join orders o on o.positioncode = p.positioncode 
where total>p.showcount and @curdate between startdate and enddate

       set @days = @days-1    
        end
       select distinct(orderid) from @temptable 
     go

评论

  
2008-06-28 10:36 | allies
丫的 我DB太差了~~ 就算技术上上去了 我看好的offer 依然还得DB好。。。杂DBA都没了吗?
  
2008-06-28 10:49 | Tony Lu      
@allies
同感,面试的时候我还问面试的人这个职位是侧重于数据库还是编程,面试的说你编什么程序也得用数据库啊,唉,什么都不说了。
  
2008-06-28 11:45 | Kingthy      
试一下这条SQL语句:

SELECT O.OrderId,O.Positioncode FROM (
SELECT D.OrderId,D.Positioncode,
(SELECT COUNT(*) FROM [Orders] T
WHERE T.Positioncode=D.Positioncode AND ((D.Startdate BETWEEN T.Startdate AND T.Enddate) OR (D.Enddate BETWEEN T.Startdate AND T.Enddate))
) AS Amount FROM [Orders] D) O
INNER JOIN [Product] P ON P.Positioncode=O.Positioncode
WHERE O.Amount > P.Showcount;


  
2008-06-28 11:49 | Kingthy      
根据你提供的数据.用我上面的那条SQL语句,返回的是如下数据表:
OrderId Positioncode
----------- ------------
1 A
4 A
7 A
8 A
3 B
6 B
2 C
10 C

也就是:
A位置中的是 1,4,7,8 (你文中说的只有1,4,7是错误的,因为四条订单都在2006-11-03号重叠)
B位置的是: 3,6
C位置的是: 2,10
  
2008-06-28 12:52 | kes.king
我有疑问,楼主第二题的数据中,OrderID=8不是从11-03播到11-05吗,那么轮播情况表中,亦即最终得到的结果集不应只是1、4、7,还应加个8吧?

因为我看完题目后,没有看你的存储过程,自己做出来的结果,广告位A是1、4、7、8.
  
2008-06-28 12:53 | kes.king
唔。。。我回了才刚看到楼上的回复。

同上~ ^_^
  
2008-06-28 12:54 | kes.king
刚才建表做题,一直没有刷新页面,做完后直接回复刷新了才看到有人更快了。
  
2008-06-28 13:01 | kes.king
是了,Kingthy兄,你的SQL语句是可以,但我之前困惑的就是不知题目是否要求结果集中包括日期,因你的结果集中无具体日期。

为了解出日期,不得以我用了临时表与存储过程,SQL想不出解决日期的方法,不知可有高见?请指教。

另外,关于C,我的结果与你不同,根据楼主的数据分析,
C,2006-11-01,1次
C,2006-11-02,3次
C,2006-11-03,3次
C,2006-11-04,2次
并未超过次数。我的结果集中不含C。

  
2008-06-28 13:05 | 阿滨       
你是要面试程序还是dba啊,真是的.!!!
知名的网络公司dba的事情还要你来做啊!
  
2008-06-28 13:06 | kes.king
POSITIONCODE ORDERID SHOWDATE SHOWCOUNT DEFAULTSHOWCOUNT
A 1 2006-11-3 4 2
A 4 2006-11-3 4 2
A 7 2006-11-3 4 2
A 8 2006-11-3 4 2
B 3 2006-11-2 2 1
B 6 2006-11-2 2 1
B 3 2006-11-3 2 1
B 6 2006-11-3 2 1
B 3 2006-11-4 2 1
B 6 2006-11-4 2 1

B在2、3、4号均超次数。
  
2008-06-28 13:14 | Tony Lu      
@Kingthy
@kes.king
抱歉,是我弄错了,已修改orderid=8的开始日期。
  
2008-06-28 13:15 | Tony Lu      
@阿滨
不是dba,呵呵。
  
2008-06-28 13:35 | Kingthy      
@kes.king
嗯.刚才是我输入错了样例数据导致的.我刚才再检查一篇.发现C应该是所有都符合.也即结果应该是如下:
OrderId Positioncode
----------- ------------
1 A
4 A
7 A
8 A
3 B
6 B
5 C
9 C
2 C
10 C

在2006-11-02时,C的2,5,10重叠.所以符合答案,
在2006-11-03时,C的2,9,10也重叠,所以也符合答案.
  
2008-06-28 13:43 | tempdb
Declare @Dup table (TmpDate datetime)
Declare @minDate datetime,@maxDate datetime
SELECT @minDate=MIN(StartDate),@maxDate=Max(EndDate) FROM Orders
WHILE @minDate<=@MaxDate
BEGIN
INSERT INTO @Dup VALUES (@minDate)
SET @minDate=@minDate+1
END

SELECT distinct aa.*
FROM
Orders aa INNER JOIN
(
SELECT Positioncode,tmpdate,count(*) as cnt
FROM Orders a,@Dup b
where tmpdate between a.startdate and a.enddate
group by Positioncode,tmpdate
)bb
ON aa.PositionCode=bb.PositionCode AND bb.tmpDate Between aa.StartDate AND aa.ENdDate
INNER JOIN Product cc ON bb.PositionCode=cc.PositionCode
WHERE bb.cnt>cc.showcount
  
2008-06-28 13:55 | hehehe
select a.OrderID, a.Positioncode,
datediff(day,a.Startdate, a.Enddate) + 1 as diff, b.Showcount
from Orders a
inner join Product b on a.Positioncode = b.Positioncode
where (datediff(day,a.Startdate, a.Enddate) + 1) > b.showcount
order by OrderID
  
2008-06-28 15:05 | kes.king
@Kingthy

C的showcount是3次哦,呵呵,大于3才算超过吧。
  
2008-06-28 15:31 | 代码乱了      
--创建函数
CREATE  FUNCTION getAllDate 

    
@Startdate datetime , @Enddate datetime 

RETURNS @t TABLE ( date datetime ) 
AS 
BEGIN 
    
DECLARE @time datetime 
    
SET @time = @Startdate 
    
WHILE ( @time <= @Enddate ) 
    
BEGIN 
        
INSERT INTO @t 
        
SELECT @time 

        
SET @time = dateadd ( day , 1 , @time ) 
    
END 
    
RETURN 
END 
GO

DECLARE @minDate datetime , @maxDate datetime 
SELECT 
    
@minDate = min ( Startdate ) , 
    
@maxDate = max ( Enddate ) 
FROM Orders 

SELECT orderid FROM Orders 
WHERE Positioncode IN 

    
SELECT a.Positioncode FROM 
    ( 
        
SELECT 
            Positioncode , 
            date , 
            
count ( date ) AS Showcount 
        
FROM Orders a 
            
INNER JOIN 
            ( 
                
SELECT * FROM dbo.getAllDate ( @minDate , @maxDate ) 
            ) 
            t 
ON t.date BETWEEN Startdate AND Enddate 
        
GROUP BY Positioncode , date 
    ) 
    
AS a , Product 
    
WHERE Product.Positioncode = a.Positioncode 
        
AND a.Showcount > Product.Showcount 



  
2008-06-28 15:35 | 代码乱了      
我的思路和博主的差不多呵呵,花了半个小时啊
  
2008-06-28 15:47 | Kingthy      
@kes.king

-_-#嗯,第二次我才输入错误了数据,我把C输入成了2,汗..

PS:我的那个SQL语句是错的.看来一句是不行滴..
  
2008-06-28 16:07 | walkinhill
Select * from orders
Where
'2006-11-03' Between StartDate and dateadd(day,1,EndDate) and
Positioncode in
(
Select
P.PositionCode
From
Product P
Inner Join
(
Select PositionCode,Count(*) as CNT
From Orders
Where '2006-11-03' Between StartDate and dateadd(day,1,EndDate)
Group by PositionCode
) O
On
P.PositionCode = o.PositionCode
Where
o.CNT > P.ShowCount
) And PositionCode = 'A'

结果集:
OrderID PositionCode StartDate EndDate
----------- -------------------- ----------------------- -----------------------
1 A 2006-11-01 00:00:00.000 2006-11-03 00:00:00.000
4 A 2006-11-03 00:00:00.000 2006-11-04 00:00:00.000
7 A 2006-11-02 00:00:00.000 2006-11-03 00:00:00.000

结果集:

  
2008-06-28 16:27 | 边城浪
第一个.这样写很简单:
SELECT * FROM Sales AS A WITH(NOLOCK)
WHERE Total>(SELECT avg(Total) From Sales AS T WHERE A.Region=T.Region)
  
2008-06-28 17:01 | xs

declare @FMinDate datetime
declare @FMaxDate datetime

set @FMinDate = (select min(fstartdate) from xs_Orders)
set @FMaxDate = (select max(fenddate) from xs_Orders)

declare @Days int
Set @Days = datediff(day,@FMinDate,@FMaxDate)

create table #Temp
(
ShowCount int,
FPositionCode varchar(100)
)

declare @step int
set @step=1
while @step <= @days
begin
declare @currentDay datetime
Set @CurrentDay = dateadd(day,@step,@FMinDate)
insert into #temp
Select count(*) as ShowCount,FPositionCode from xs_Orders where fstartdate <= @CurrentDay and fenddate >=@CurrentDay group by FPositionCode
set @step = @step + 1
end

select distinct c.* from #temp a
inner join xs_Product b on b.FPositionCode=a.FPositionCode
inner join xs_Orders c on c.FPositionCode=a.FPositionCode
where b.FCount < a.ShowCount

drop table #temp

  
2008-06-28 18:12 | HelloCode      
第二题感觉有问题,像广告这一类的,在添加广告的时候就应该可以显示那些日期还有空余的广告位。这种题目不符合实际。
  
2008-06-28 18:25 | kes.king
@HelloCode
题目中说明了,销售人员是不care这个限制的。
可能在一个销售人员正在填写还未提交的时候,另一个销售人员已经成功跟客户接下了订单,因此他也需要填写提交。

我认为很符合实际。

 来自:一家公司的数据库面试题

分类: 数据库开发 数据仓库 Web技术



关于酷勤 | 联系方式 | 免责声明 | 友情链接