Я хочу добавить в мою базу данных столбец, который выполняет построчную кумулятивную конкатенацию значений другого столбца для каждого идентификатора и упорядочивает результирующую строку по другой иерархии. Набор данных очень большой, и результат, который я разработал для меньших тестовых данных, не работает в более широком масштабе, поэтому мне нужна помощь в его редизайне.
На данный момент я написал запрос, используя комбинацию рекурсивного CTE для выполнения кумулятивной конкатенации (вывод шага 1 ниже), а затем немного неуклюжей функции (вывод шага 2 ниже), чтобы упорядочить строки в соответствии с отдельной иерархией который также удаляет значение «1». Они работают на небольшом подмножестве моих данных (n = 60), но когда я пытаюсь запустить большее подмножество (n = 500 000), таблица CTE запускается вечно (останавливается без завершения в 2 часа). Реальный набор данных будет иметь порядок сотен миллионов строк, поэтому решение не подходит для такого масштаба.
ID Start_Date End_Date Seg step1 step2
1 01/04/1946 31/12/1990 1 1 1
1 01/01/1991 08/01/2007 4 4 4
1 09/01/2007 04/02/2007 1 1 1
1 05/02/2007 18/10/2017 4 14 4
1 01/04/2013 18/10/2017 8 148 48
1 11/11/2014 18/10/2017 7 1487 487
2 01/05/1931 31/12/1997 1 1 1
2 01/01/1998 20/01/2014 4 4 4
2 31/01/2011 20/01/2014 6 146 46
2 21/02/2013 20/01/2014 5 1465 456
2 01/04/2013 20/01/2014 8 14658 4586
2 29/04/2013 20/01/2014 7 146587 45876
Существуют дополнительные сложные логические элементы, такие как запуск кумуляции только тогда, когда дата начала предшествует дате окончания предыдущей строки, поэтому ключевым является решение, которое обеспечивает гибкость путем добавления операторов where
или case when
.
Пример рекурсивного CTE и функции упорядочения, которые я использовал (не адаптированные для показанной упрощенной таблицы, но указывающие на структуру, которую я использовал) приведены ниже.
Рекурсивный CTE (столбец шага вывода 1)
with t (ID, Segment,start_date, start_comb,updated_end_date ,rn) as (
select ID, Segment, start_date, case when Segment_end_date <> resolved_date OR Segment_end_date is null then 1 else 0 end as start_comb
,updated_end_date
,row_number() over (partition by ID order by start_date) as rn
from #test_IDs
)
,r (ID, orig_seg, Segment, rn, start_comb, start_date, updated_end_date) as (
select ID, cast(Segment as varchar(max)), cast(Segment as varchar(max)),rn, start_comb, start_date, updated_end_date
from t
where start_comb=0
union all
select r.ID, cast(t.segment as varchar(max)) as orig_seg
, Segment = cast( (concat(r.Segment,t.Segment)) as varchar(max))
, t.rn, t.start_comb, t.start_date, t.updated_end_date
from r
join t on t.ID = r.ID and t.rn = r.rn + 1 and t.start_comb <> 0
)
Функция заказа (столбец шага 2 вывода)
if object_id ('reformat') is not null
drop function reformat
create function dbo.reformat
(
@unordered_Segs varchar(max)
)
returns varchar(255)
as
begin
declare @healthy int, @first int, @second int, @third int, @fourth int, @fifth int, @outtext int
if Charindex('4',@unordered_segs) > 0
set @first = 4
else set @first = ''
if Charindex('5',@unordered_segs) > 0
set @second = 5
else set @second = ''
if Charindex('8',@unordered_segs) > 0
set @third = 8
else set @third = ''
if Charindex('7',@unordered_segs) > 0
set @fourth = 7
else set @fourth = ''
if Charindex('6',@unordered_segs) > 0
set @fifth = 6
else set @fifth = ''
if Charindex('1',@unordered_segs) > 0 and len(@unordered_segs) = 1
set @outtext = 1
else
set @outtext = Replace((concat(@first,@second,@third,@fourth,@fifth)),'0','')
return @outtext
end
Спасибо!