2014-11-22 123 views
2

根据未取消日​​期选择第一个活动以及是否取消所有活动以选择第一个活动的最佳方法是什么?Top 1 with where子句 - 如果没有找到记录,则忽略where子句

方案有样本数据:

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月3日 - 0

活动4 - 十二分之二千零一十四/ 07 - 1

活动6 - 2014/12/0 9 - 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 

SQL Fiddle link

回答

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

+0

这实际上是有道理的......我太过于复杂。我也用'row_number'试过了,没有成功。感谢你! – Hatsjoem 2014-11-22 22:37:21