作者:Tony Lu 来源:博客园 酷勤网收集 2008-06-29
前两天收到一家知名互联网公司的offer(具体哪家公司就不说了^_^),是去做公司内部的MIS系统,使用Asp或Java语言,虽然本人对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这天有三个广告(1、4、7),对于广告位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
评论
同感,面试的时候我还问面试的人这个职位是侧重于数据库还是编程,面试的说你编什么程序也得用数据库啊,唉,什么都不说了。
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;
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
因为我看完题目后,没有看你的存储过程,自己做出来的结果,广告位A是1、4、7、8.
同上~ ^_^
为了解出日期,不得以我用了临时表与存储过程,SQL想不出解决日期的方法,不知可有高见?请指教。
另外,关于C,我的结果与你不同,根据楼主的数据分析,
C,2006-11-01,1次
C,2006-11-02,3次
C,2006-11-03,3次
C,2006-11-04,2次
并未超过次数。我的结果集中不含C。
知名的网络公司dba的事情还要你来做啊!
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号均超次数。
@kes.king
抱歉,是我弄错了,已修改orderid=8的开始日期。
不是dba,呵呵。
嗯.刚才是我输入错了样例数据导致的.我刚才再检查一篇.发现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也重叠,所以也符合答案.
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
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
C的showcount是3次哦,呵呵,大于3才算超过吧。
--创建函数
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
) 

-_-#嗯,第二次我才输入错误了数据,我把C输入成了2,汗..
PS:我的那个SQL语句是错的.看来一句是不行滴..
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
结果集:
SELECT * FROM Sales AS A WITH(NOLOCK)
WHERE Total>(SELECT avg(Total) From Sales AS T WHERE A.Region=T.Region)
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
题目中说明了,销售人员是不care这个限制的。
可能在一个销售人员正在填写还未提交的时候,另一个销售人员已经成功跟客户接下了订单,因此他也需要填写提交。
我认为很符合实际。
来自:一家公司的数据库面试题

