Конечно, редизайн таблицы значительно упростит этот запрос, но иногда нам просто нужно выполнить его. Я написал следующий запрос, используя несколько CTE; Я считаю, что легче следовать и точно видеть, что происходит, но вы можете упростить это, когда освоите технику.
Чтобы вставить ваш основной ряд "P", вы увидите, что я просто поместил его в столбец Associate, но его лучше поместить в простой UNION вне CTE.
Кроме того, если вы решите провести рефакторинг своей схемы, можно использовать метод ниже, чтобы «разбить» столбец Associate на строки.
;with
Split (MemberNumber, JoinDate, AssociateItem)
as ( select MemberNumber, JoinDate, p.n.value('(./text())[1]','varchar(25)')
from ( select MemberNumber, JoinDate, n=cast('<n>'+replace(Associate + ' P',' ','</n><n>')+'</n>' as xml).query('.')
from @t
) a
cross apply n.nodes('n') p(n)
)
select MemberNumber + '-' + AssociateItem,
JoinDate
from Split
where left(AssociateItem, 1) in ('A','P')
order
by MemberNumber;
Метод XML не является хорошим вариантом с точки зрения производительности, так как его скорость уменьшается по мере увеличения количества элементов в «массиве». Если у вас длинные массивы, вам может пригодиться следующий подход:
--* should be physical table, but use this cte if needed
--;with
--number (n)
--as ( select top(50) row_number() over(order by number) as n
-- from master..spt_values
-- )
select MemberNumber + '-' + substring(Associate, n, isnull(nullif(charindex(' ', Associate + ' P', n)-1, -1), len(Associate)) - n+1),
JoinDate
from ( select MemberNumber, JoinDate, Associate + ' P' from @t
) t (MemberNumber, JoinDate, Associate)
cross
apply number n
where n <= convert(int, len(Associate)) and
substring(' ' + Associate, n, 1) = ' ' and
left(substring(Associate, n, isnull(nullif(charindex(' ', Associate, n)-1, -1), len(Associate)) - n+1), 1) in ('A', 'P');