На самом деле, вы можете получить пару довольно простых решений, использующих функции ранжирования / управления окнами и / или CTE и рекурсивные CTE .
Создайте процедуру, которая принимает символьный список значений кода, разделенных запятыми, которые вы ищете в последовательности, в которой вы хотите их использовать - используйте любой из дюжины возможных способов разбить этот список на таблицу / набор , который состоит из последовательности и значения кода, в результате получается таблица со структурой, подобной этой:
declare @sequence table (sequence int not null, Code int not null);
Как только вы это сделаете, вам просто нужно упорядочить исходный набор на основе присоединения упорядоченной таблицы к исходной таблице с теми же значениями кода для данного ItemId - как только вы отфильтруете и упорядочите исходный набор, вы можете просто присоединиться снова на основе соответствующих значений последовательности - это звучит сложно, но на самом деле это будет один запрос, подобный следующему:
with srcData as (
select row_number() over(order by t.EffectiveDate) as rn,
t.TransactionId, t.ItemId, t.Code, t.EffectiveDate, t.CreateDate
from #TableName t
join @sequence s
on t.Code = s.Code
where t.ItemId = @item_id
)
select d.TransactionId, d.ItemId, d.Code, d.EffectiveDate, d.CreateDate
from srcData d
join @sequence s
on d.rn = s.sequence
and d.Code = s.Code
order by d.rn;
Само по себе это не гарантирует, что вы получите набор результатов, идентичный тому, что вы ищете, но размещение данных во временной таблице и добавление нескольких простых проверок вокруг кода поможет (например, , добавить проверку контрольной суммы и сумму значений кода)
declare @tempData table (rn int, TransactionId smallint, ItemId smallint, Code smallint, EffectiveDate datetime, CreateDate datetime);
with srcData as (
select row_number() over(order by t.EffectiveDate) as rn,
t.TransactionId, t.ItemId, t.Code, t.EffectiveDate, t.CreateDate
from #TableName t
join @sequence s
on t.Code = s.Code
where t.ItemId = @item_id
)
insert @tempData
(rn, TransactionId, ItemId, Code, EffectiveDate, CreateDate)
select d.rn, d.TransactionId, d.ItemId, d.Code, d.EffectiveDate, d.CreateDate
from srcData d
join @sequence s
on d.rn = s.sequence
and d.Code = s.Code;
-- Verify we have matching hash/sums
if
(
( (select sum(Code) from @sequence) = (select sum(Code) from @tempData) )
and
( (select checksum_agg(checksum(sequence, Code)) from @sequence) = (select checksum_agg(checksum(rn, Code)) from @tempData) )
)
begin;
-- Match - return the resultset
select d.TransactionId, d.ItemId, d.Code, d.EffectiveDate, d.CreateDate
from @tempData d
order by d.rn;
end;
Если вы хотите сделать все это встроенным, вы можете использовать другой подход, используя CTE и рекурсию, чтобы выполнить текущую сумму / итоговое сравнение, а также сравнение, подобное OrdPath (хотя вам все равно придется анализировать данные последовательности символов) в набор данных)
-- Sequence data with running total
with sequenceWithRunningTotal as
(
-- Anchor
select s.sequence, s.Code, s.Code as runningTotal, cast(s.Code as varchar(8000)) as pth,
sum(s.Code) over(partition by 1) as sumCode
from @sequence s
where s.sequence = 1
-- Recurse
union all
select s.sequence, s.Code, b.runningTotal + s.Code as runningTotal,
b.pth + '.' + cast(s.Code as varchar(8000)) as pth,
b.sumCode as sumCode
from @sequence s
join sequenceWithRunningTotal b
on s.sequence = b.sequence + 1
),
-- Source data with sequence value
srcData as
(
select row_number() over(order by t.EffectiveDate) as rn,
t.TransactionId, t.ItemId, t.Code, t.EffectiveDate, t.CreateDate,
sum(t.Code) over(partition by 1) as sumCode
from #TableName t
join @sequence s
on t.Code = s.Code
where t.ItemId = @item_id
),
-- Source data with running sum
sourceWithRunningSum as
(
-- Anchor
select t.rn, t.TransactionId, t.ItemId, t.Code, t.EffectiveDate, t.CreateDate,
t.Code as runningTotal, cast(t.Code as varchar(8000)) as pth,
t.sumCode
from srcData t
where t.rn = 1
-- Recurse
union all
select t.rn, t.TransactionId, t.ItemId, t.Code, t.EffectiveDate, t.CreateDate,
s.runningTotal + t.Code as runningTotal,
s.pth + '.' + cast(t.Code as varchar(8000)) as pth,
t.sumCode
from srcData t
join sourceWithRunningSum s
on t.rn = s.rn + 1
)
select d.TransactionId, d.ItemId, d.Code, d.EffectiveDate, d.CreateDate
from sourceWithRunningSum d
join sequenceWithRunningTotal s
on d.rn = s.sequence
and d.Code = s.Code
and d.runningTotal = s.runningTotal
and d.pth = s.pth
and d.sumCode = s.sumCode
order by d.rn;