2013-04-04 7 views
0

Я новичок в SQL Server с довольно сложной задачей SQL, и ни одно из решений, которые я нашел до сих пор, не подходит для моей проблемы ниже.Членство в SQL Server Дата Диапазон

У меня есть таблица базы данных, в которой в настоящее время содержится информация о членстве, объединяющая информацию (выдержка ниже) с одной строкой за каждый год/период, который член заплатил за членство; Член может отменить свое членство на один год/период и воссоединиться позднее. Мы должны представлять каждое непрерывное членство в один линии такого содержания экстракта-ниже становлюсь Extract 2:

экстракт 1

Member_No Start_Date     End_Date 
--------- ----------     -------- 
10  2010-01-01 00:00:00.000 2011-01-01 00:00:00.000 
10  2011-01-01 00:00:00.000 2012-01-01 00:00:00.000 
10  2012-01-01 00:00:00.000 2013-01-01 00:00:00.000 
10  2013-01-01 00:00:00.000 2014-01-01 00:00:00.000 
20  2005-01-01 00:00:00.000 2006-01-01 00:00:00.000 
20  2006-01-01 00:00:00.000 2007-01-01 00:00:00.000 
20  2007-01-01 00:00:00.000 2008-01-01 00:00:00.000 
30  2005-01-01 00:00:00.000 2006-01-01 00:00:00.000 
30  2006-01-01 00:00:00.000 2007-01-01 00:00:00.000 
30  2007-01-01 00:00:00.000 2008-01-01 00:00:00.000 
30  2008-01-01 00:00:00.000 2009-01-01 00:00:00.000 
30  2009-01-01 00:00:00.000 2010-01-01 00:00:00.000 
30  2010-10-13 00:00:00.000 2011-01-01 00:00:00.000 
30  2011-01-01 00:00:00.000 2012-01-01 00:00:00.000 
30  2012-01-01 00:00:00.000 2013-01-01 00:00:00.000 

Мне нужно заменить содержимое приведенных выше таблиц с ниже - есть много больше записей в таблице, о котором идет речь, и я был бы весьма признателен любой помощник любого может предложить:

Extract 2

Member_No Start_Date     End_Date 
--------- ----------     -------- 
10  2010-01-01 00:00:00.000 2014-01-01 00:00:00.000 
20  2005-01-01 00:00:00.000 2008-01-01 00:00:00.000 
30  2005-01-01 00:00:00.000 2010-01-01 00:00:00.000 
30  2010-10-13 00:00:00.000 2013-01-01 00:00:00.000 

ответ

0

Вот лучший подход (оригинальный подход еще ниже):

with ms as (
     select ms.*, 
      (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and cast(ms2.Start_date as date) = cast(ms.End_date as date) 
      ) as LinkedToNext 
     from MemberShip ms 
    ) 
select member_no, MIN(start_date) as start_date, MAX(end_date) as end_date 
from (select ms.*, 
      (select top 1 end_date 
       from ms ms2 where ms2.Member_no = ms.Member_No and ms2.LinkedToNext is NULL and ms2.Start_Date >= ms.Start_Date 
      order by end_date desc 
      ) as grouping 
     from ms 
    ) ms1 
group by Member_no, grouping 

СТЕ определяет, будет ли что-то связано с другой. Группировка - это дата окончания первой записи после , а не, связанная со следующей для связанной цепи, это всегда одно и то же.

В ответ на ваш комментарий о «более чем одной строке». Это означает, что член имеет два членства, начиная с той же даты. Если это единственная форма перекрытия, вы можете исправить это как:

with ms as (
     select member_no, start_date, max(end_date) as end_date 
      (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and cast(ms2.Start_date as date) = cast(ms.End_date as date) 
      ) as LinkedToNext 
     from MemberShip ms 
     group by member_no, start_date 
    ) 

Гораздо проще, чем мой оригинальный подход, который я все еще держа ниже:

with ms as (
     select ms.*, 
      (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and ms2.Start_date = ms.End_date 
      ) as LinkedToNext, 
      (select ms2.End_Date from Membership ms2 where ms2.Member_no = ms.Member_no and ms2.Start_date = ms.End_date 
      ) as NextEndDate, 
       (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and ms2.End_date = ms.Start_date 
      ) as LinkedToPrev 
     from MemberShip ms 
    ) 
select member_no, MIN(start_date) as start_date, 
     MAX(coalesce(NextEndDate, End_Date)) as end_date 
from (select ms.*, 
      (ROW_NUMBER() over (partition by Member_no order by Start_Date) - 
       ROW_NUMBER() over (partition by Member_no, LinkedToNext order by Start_date) 
      ) as grouping 
     from ms 
    ) ms1 
where not (LinkedToNext is null and LinkedToPrev = 1) 
group by member_no, grouping 

Это использует коррелированных subquer для определите, связано ли одно членство со следующим (в зависимости от даты начала, такой же, как и дата окончания - вы можете действительно добавить фактор вымывания, если хотите).

Затем он использует трюк. Он перечисляет строки по start_date для каждого члена. Он также перечисляет строки по дате начала для каждого члена, независимо от того, связаны они или нет. Разница постоянна для цепочки, которая может быть сгруппирована вместе.

Последний шаг - сгруппировать это, чтобы получить окончательный результат.

Одно осложнение получает правильную дату окончания. Исходный код не включает конец цепочки в вычислении. Итак, я беру дату окончания из следующей записи. Затем он отфильтровывает эту финальную запись.

+0

Эй, Гордон, спасибо за ваш ответ. – Babs

+0

Эй, Гордон, спасибо за ваш ответ. Результат первого сообщения ближе к тому, чего я пытаюсь достичь; однако он содержит дополнительные строки - не могли бы вы помочь с обновленным SQL для удаления строк 2, 4, 7 и 8?(В результате работы вашего SQL против предоставленных данных в мой оригинальный пост ниже) 'member_no \t \t start_date датой_окончания 2010-01-01 \t 2014-01-01 2013-01-01 \t 2014-01 -01 2005-01-01 \t 2008-01-01 2007-01-01 \t 2008-01-01 2005-01-01 \t 2010-01-01 2010-10 -13 \t 2013-01-01 2009-01-01 \t 2010-01-01 2012-01-01 \t 2013-01-01' – Babs

+0

@Babs. , , Виноват. Во втором коррелированном подзапросе я оставил «порядок». –