前两天收到一家知名互联网公司的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
posted on 2008-06-28 10:13
Tony Lu 阅读(5015)
评论(33) 编辑 收藏 所属分类:
test
发表评论
丫的 我DB太差了~~ 就算技术上上去了 我看好的offer 依然还得DB好。。。杂DBA都没了吗?
@allies
同感,面试的时候我还问面试的人这个职位是侧重于数据库还是编程,面试的说你编什么程序也得用数据库啊,唉,什么都不说了。
试一下这条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;
根据你提供的数据.用我上面的那条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
我有疑问,楼主第二题的数据中,OrderID=8不是从11-03播到11-05吗,那么轮播情况表中,亦即最终得到的结果集不应只是1、4、7,还应加个8吧?
因为我看完题目后,没有看你的存储过程,自己做出来的结果,广告位A是1、4、7、8.
唔。。。我回了才刚看到楼上的回复。
同上~ ^_^
刚才建表做题,一直没有刷新页面,做完后直接回复刷新了才看到有人更快了。
是了,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。
你是要面试程序还是dba啊,真是的.!!!
知名的网络公司dba的事情还要你来做啊!
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号均超次数。
@Kingthy
@kes.king
抱歉,是我弄错了,已修改orderid=8的开始日期。
@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也重叠,所以也符合答案.
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
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
@Kingthy
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
)


@kes.king
-_-#嗯,第二次我才输入错误了数据,我把C输入成了2,汗..
PS:我的那个SQL语句是错的.看来一句是不行滴..
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
结果集:
第一个.这样写很简单:
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
第二题感觉有问题,像广告这一类的,在添加广告的时候就应该可以显示那些日期还有空余的广告位。这种题目不符合实际。
@HelloCode
题目中说明了,销售人员是不care这个限制的。
可能在一个销售人员正在填写还未提交的时候,另一个销售人员已经成功跟客户接下了订单,因此他也需要填写提交。
我认为很符合实际。
@kes.king
像这种情况在提交合同后在检测出来,肯定还是要再修改的,这就比较浪费时间了。
如果是一个销售人员提交的时候,另外一销售人员先提交了,在后提交的销售人员提交合同时就应该提示这段时间日期已经满了,需要做修改。然后再提交修改后的合同,提交需要肯定修改的合同感觉没有意义,无法安排广告的合同总不能就这样吧。这题目有问题。
--try:
declare @mindate datetime, @maxdate datetime
select @mindate=min(startdate),@maxdate=max(enddate) from orders
create table #dt(ErrorDay datetime)
while @mindate<=@maxdate
begin
insert into #dt values(@mindate)
select @mindate=dateadd(day,1,@mindate)
end
select d.*,c.showcount from product c,
(select b.positioncode ,a.ErrorDay,ErrorCount=count(1) from #dt a,orders b where a.ErrorDay between b.startdate and b.enddate group by a.ErrorDay,b.positioncode) d
where c.positioncode=d.positioncode and d.ErrorCount>c.showcount
drop table #dt
测试通过
DROP TABLE #Temp
CREATE TABLE #Temp
(
OrderID INT,
Positioncode NCHAR(10),
InDate DATETIME,
);
DECLARE @minId int,@maxID int;
SELECT @minId = min(orderid),@maxid = max(orderid) FROM Orders;
WHILE(@minId<=@maxid)
BEGIN
DECLARE @StartDate DATETIME,@EndDate DATETIME
DECLARE @Positioncode NCHAR(10)
SELECT @Positioncode = Positioncode,
@StartDate = StartDate,
@EndDate = EndDate
FROM dbo.Orders
WHERE OrderID = @minId;
WHILE(@StartDate<=@EndDate)
BEGIN
INSERT INTO #Temp(OrderID, Positioncode, InDate)
VALUES (@minId, @Positioncode, @StartDate);
SET @StartDate = DATEADD(DAY,1,@StartDate);
END
SET @minId = @minId + 1
END
WITH X AS
(
SELECT T.*
FROM (SELECT Positioncode,InDate,Count(1) AS Numbers FROM #Temp
GROUP BY Positioncode,InDate) AS T
INNER JOIN dbo.Product AS P
ON T.Positioncode = P.Positioncode
AND T.Numbers > P.Showcount
--ORDER BY T.Positioncode,T.InDate
)
SELECT A.OrderID,A.Positioncode,X.InDate,X.Numbers
FROM dbo.Orders AS A
INNER JOIN X
ON A.Positioncode = X.Positioncode
AND X.InDate BETWEEN A.StartDate AND A.EndDate
ORDER BY X.Positioncode,X.InDate
执行结果为:
1 A 2006-11-03 00:00:00.000 3
4 A 2006-11-03 00:00:00.000 3
7 A 2006-11-03 00:00:00.000 3
3 B 2006-11-02 00:00:00.000 2
6 B 2006-11-02 00:00:00.000 2
3 B 2006-11-03 00:00:00.000 2
6 B 2006-11-03 00:00:00.000 2
3 B 2006-11-04 00:00:00.000 2
6 B 2006-11-04 00:00:00.000 2
用SQL2005重新写了个...
WITH T AS
(
SELECT A.*,
(SELECT COUNT(1) FROM dbo.Orders AS B
WHERE A.Positioncode = B.Positioncode
AND A.Startdate >= B.Startdate AND A.Startdate <= B.Enddate
) AS Counts1
,(SELECT COUNT(1) FROM dbo.Orders AS B
WHERE A.Positioncode = B.Positioncode
AND A.Enddate >= B.Startdate AND A.Enddate <= B.Enddate
) AS Counts2
FROM dbo.Orders AS A
)
SELECT T.OrderID, T.Positioncode, (CASE WHEN T.Counts1>T.Counts2
THEN T.Counts1
ELSE T.Counts2 END) AS Counts
FROM T
INNER JOIN dbo.Product AS P
ON T.Positioncode = P.Positioncode
AND P.Showcount < (CASE WHEN T.Counts1 > T.Counts2
THEN T.Counts1
ELSE T.Counts2 END)
ORDER BY Positioncode
运行结果:
1 A 3
4 A 3
7 A 3
6 B 2
3 B 2
select a.*, (
select count(*) from product b where a.Positioncode = b.Positioncode
)as c from orders a
小弟不才,上面语句看了半天没明白,请教前辈解释一下,多谢了!
为什么能a.Positioncode = b.Positioncode?
我只见过
(select count(*) from product b,product a where a.Positioncode = b.Positioncode)
这样的
明显有区别,但实在琢磨不透啊...闹心啊!!
@菜鸟请教一个Sql
(
select count(*)
from product b
where a.Positioncode = b.Positioncode
)as c
相当一个属性列,被命名为C
结果表