按日期选择第一个未取消的活动的最佳方法是什么,如果取消所有活动以选择第一个活动。
带样本数据的方案:
create table SomeOtherTable
(
Id bigint primary key
)
create table activities
(
Id bigint identity(1,1) primary key,
SomeForeignKey bigint,
Description varchar(100),
Date datetime,
Canceled bit
)
insert into SomeOtherTable values (1),(2),(3)
insert into activities values (1, 'Activity 1', '20141201', 1),
(1, 'Activity 2', '20141203', 0),
(1, 'Activity 3', '20141205', 0),
(2, 'Activity 4', '20141207', 1),
(2, 'Activity 5', '20141209', 1),
(3, 'Activity 6', '20141209', 0)
期望的输出:
活动2 - 2014/12/03 - 0
活动4 - 2014/12/07 - 1
活动6 - 2014/12/09 - 0
我目前正在使用此查询,但我认为必须有更好的解决方案......
select case when a1.Id is null then a2.Description else a1.Description end as Description,
case when a1.Id is null then a2.Date else a1.Date end as Date,
case when a1.Id is null then a2.Canceled else a1.Canceled end as Canceled
from SomeOtherTable t
outer apply (select top 1 *
from activities a
where t.id=a.SomeForeignKey
and a.Canceled = 0
order by a.Date) a1
cross apply (select top 1 *
from activities a
where t.id=a.SomeForeignKey
order by a.Date) a2
答案 0 :(得分:2)
您希望优先处理结果,首先是Canceled = 0
,然后是任何其他行。您可以使用一个outer apply
:
select a.Description, a.Date, a.Canceled
from SomeOtherTable t outer apply
(select top 1 *
from activities a
where t.id = a.SomeForeignKey
order by (case when a.canceled = 0 then 1 else 0 end) desc, a.Date
) a;
我通常会在row_number()
计算中加入类似的逻辑,但outer apply
的效果也一样。
编辑:
为了完整性和比较,这里是row_number()
方法:
select a.Description, a.Date, a.Canceled
from SomeOtherTable t left join
(select a.*,
row_number() over (partition by a.SomeForeignKey
order by (case when a.canceled = 0 then 1 else 0 end) desc, a.Date
) as seqnum
from activities a
) a
on t.id = a.SomeForeignKey and seqnum = 1;
一般来说,我认为apply
方法要快一点 - 基本上,它会在第一个匹配行停止,并且不需要继续处理给定t.id
。