2015-10-15 6 views
1

У меня есть огромные данные и образец таблицы выглядит, как показано нижеОбновление с помощью автообъединение Sql Server

+-----------+------------+-----------+-----------+ 
| Unique_ID | Date | RowNumber | Flag_Date | 
+-----------+------------+-----------+-----------+ 
|   1 | 6/3/2014 |   1 | 6/3/2014 | 
|   1 | 5/22/2015 |   2 | NULL  | 
|   1 | 6/3/2015 |   3 | NULL  | 
|   1 | 11/20/2015 |   4 | NULL  | 
|   2 | 2/25/2014 |   1 | 2/25/2014 | 
|   2 | 7/31/2014 |   2 | NULL  | 
|   2 | 8/26/2014 |   3 | NULL  | 
+-----------+------------+-----------+-----------+ 

Теперь мне нужно проверить, если разница между датой во 2-й строке и Flag_date в 1-м ряду. Если разница больше 180, то вторая строка Flag_date должна быть обновлена ​​с датой во второй строке, иначе она должна быть обновлена ​​Flag_date в 1 строке. И это же правило следует для всех строк с одинаковым unique_id

update a 
set a.Flag_Date=case when DATEDIFF(dd,b.Flag_Date,a.[Date])>180 then a.[Date] else b.Flag_Date end 
from Table1 a 
inner join Table1 b 
on a.RowNumber=b.RowNumber+1 and a.Unique_ID=b.Unique_ID 

Приведенный выше запрос обновления, когда выполняется один раз, только вторая строка под каждым unique_id обновляется и результат выглядит, как показано ниже

+-----------+------------+-----------+------------+ 
| Unique_ID | Date | RowNumber | Flag_Date | 
+-----------+------------+-----------+------------+ 
|   1 | 2014-06-03 |   1 | 2014-06-03 | 
|   1 | 2015-05-22 |   2 | 2015-05-22 | 
|   1 | 2015-06-03 |   3 | NULL  | 
|   1 | 2015-11-20 |   4 | NULL  | 
|   2 | 2014-02-25 |   1 | 2014-02-25 | 
|   2 | 2014-07-31 |   2 | 2014-02-25 | 
|   2 | 2014-08-26 |   3 | NULL  | 
+-----------+------------+-----------+------------+ 

И мне нужно бежать четыре раза, чтобы достичь нужного мне результата

+-----------+------------+-----------+------------+ 
| Unique_ID | Date | RowNumber | Flag_Date | 
+-----------+------------+-----------+------------+ 
|   1 | 2014-06-03 |   1 | 2014-06-03 | 
|   1 | 2015-05-22 |   2 | 2015-05-22 | 
|   1 | 2015-06-03 |   3 | 2015-05-22 | 
|   1 | 2015-11-20 |   4 | 2015-11-20 | 
|   2 | 2014-02-25 |   1 | 2014-02-25 | 
|   2 | 2014-07-31 |   2 | 2014-02-25 | 
|   2 | 2014-08-26 |   3 | 2014-08-26 | 
+-----------+------------+-----------+------------+ 

есть ли способ, где я могу запустить обновление только один раз, и все строки обновляются.

Спасибо!

ответ

1

Если вы используете SQL Server 2012+, то вы можете использовать lag():

with toupdate as (
     select t1.*, 
      lag(flag_date) over (partition by unique_id order by rownumber) as prev_flag_date 
     from table1 t1 
    ) 
update toupdate 
    set Flag_Date = (case when DATEDIFF(day, prev_Flag_Date, toupdate.[Date]) > 180 
          then toupdate.[Date] else prev_Flag_Date 
        end); 

И эта версия, и ваша версия может воспользоваться индексом на table1(unique_id, rownumber) или, еще лучше, table1(unique_id, rownumber, flag_date).

EDIT:

В более ранних версиях, это может иметь более высокую производительность:

with toupdate as (
     select t1.*, t2.flag_date as prev_flag_date 
     from table1 t1 outer apply 
      (select top 1 t2.flag_date 
      from table1 t2 
      where t2.unique_id = t1.unique_id and 
        t2.rownumber < t1.rownumber 
      order by t2.rownumber desc 
      ) t2 
    ) 
update toupdate 
    set Flag_Date = (case when DATEDIFF(day, prev_Flag_Date, toupdate.[Date]) > 180 
          then toupdate.[Date] else prev_Flag_Date 
        end); 

СТЕ может сделать использование одного и того же индекса - и это важно иметь индекс. Причина лучшей производительности - это то, что ваше соединение на row_number() не может использовать индекс в этом поле.

+0

Спасибо, Гордон. Am on 2008R2 и, следовательно, lag() не работают для меня. есть способ, которым я могу заставить этот запрос работать в 2008 году? Пожалуйста, дайте мне знать – Santosh

+0

Спасибо, Гордон. Это прекрасно работает – Santosh

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