2014-11-22 4 views
2

Каков наилучший способ выбрать первое действие по дате, которое не отменено, и если все действия отменены для выбора первого.Верх 1 с предложением where - игнорировать 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/03 - 0

активность 4 - 2014/12/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 работает так же хорошо.

EDIT:

Для полноты и сравнения, вот 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» тоже без succes tho. Спасибо за это! – Hatsjoem

Смежные вопросы