如何获取如下所示的SQL表:
MemberNumber JoinDate Associate
1234 1/1/2011 A1 free A2 upgrade A31
5678 3/15/2011 A4
9012 5/10/2011 free
输出(使用视图或写入另一个表或其他最简单的表):
MemberNumber Date
1234-P 1/1/2011
1234-A1 1/1/2011
1234-A2 1/1/2011
1234-A31 1/1/2011
5678-P 3/15/2011
5678-A4 3/15/2011
9012-P 5/10/2011
每行产生“-P”(主)输出线以及任何A#(关联)线。 Associate字段可以包含许多不同的非“A#”值,但“A#”是我感兴趣的(#从1到99)。在那个领域也可以有很多“A#”。
答案 0 :(得分:3)
当然,表格重新设计会大大简化此查询,但有时我们只需要完成它。我使用多个CTE编写了以下查询;我发现它更容易理解,看看到底发生了什么,但是一旦你掌握了这项技术,你就可以进一步简化这一过程。
要注入“P”主行,您会看到我只是将其卡入了Associate列,但最好放在CTE外部的简单UNION中。
此外,如果您确实选择重构架构,则可以使用以下技术将您的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');
答案 1 :(得分:1)
试试这个新版本
declare @t table (MemberNumber varchar(8), JoinDate date, Associate varchar(50))
insert into @t values ('1234', '1/1/2011', 'A1 free A2 upgrade A31'),('5678', '3/15/2011', 'A4'),('9012', '5/10/2011', 'free')
;with b(f, t, membernumber, joindate, associate)
as
(
select 1, 0, membernumber, joindate, Associate
from @t
union all
select t+1, charindex(' ',Associate + ' ', t+1), membernumber, joindate, Associate
from b
where t < len(Associate)
)
select MemberNumber + case when t = 0 then '-P' else '-'+substring(Associate, f,t-f) end NewMemberNumber, JoinDate
from b
where t = 0 or substring(Associate, f,1) = 'A'
--where t = 0 or substring(Associate, f,2) like 'A[1-9]'
-- order by MemberNumber, t
结果与请求的输出相同。
答案 2 :(得分:0)
我建议您通过添加链接表而不是“关联”列来更改数据库结构。链接表将包含两个或更多列,如下所示:
MemberNumber Associate Details
-----------------------------------
1234 A1 free
1234 A2 upgrade
1234 A31
5678 A4
然后可以通过简单的JOIN获得所需的结果:
SELECT CONCAT(m.`MemberNumber`, '-', 'P'), m.`JoinDate`
FROM `members` m
UNION
SELECT CONCAT(m.`MemberNumber`, '-', IFNULL(a.`Associate`, 'P')), m.`JoinDate`
FROM `members` m
RIGHT JOIN `members_associates` a ON m.`MemberNumber` = a.`MemberNumber`