我希望在指定位置将一组值插入给定的字符串中。为此,我找不到现有的解决方案,因此创建了下面的查询。我想知道是否有一种方法可以简化它,特别是查询cte并创建NewString的部分。此外,是否有一种方法可以在不涉及ID列的情况下构造cte递归?ID (和其他部分)似乎很好,只是想知道是否可以对其进行调整,使其更加有机/优雅,或者总体上是否有更好的解决方案。不同的组实际上只用于测试;每个组对应一个可能的插入位置场景。因此,当我使用它时,不会有任何团体参与。
declare
@String varchar(200),
@StringLen int,
@GroupID int,
@PositionMax int
declare @Chars table (
ID int identity,
GroupID int,
Position int,
Value varchar(20)
)
select
@String = 'abcde',
@StringLen = len(@String),
@GroupID = 1
--Affix
--[P]refix
--[I]nfix
--[S]uffix
insert @Chars
select
GroupID,
Position,
Value
from (
values
(1, 0, 'X'), --P
(2, 2, 'Y'), --I
(3, 5, 'Z'), --S
(4, 0, 'X'), --P
(4, 2, 'Y'), --I
(5, 2, 'Y'), --I
(5, 5, 'Z'), --S
(6, 0, 'X'), --P
(6, 5, 'Z'), --S
(7, 0, 'X'), --P
(7, 2, 'Y'), --I
(7, 5, 'Z'), --S
(8, 2, 'Y1'), --I
(8, 4, 'Y2'), --I
(9, 0, 'X'), --P
(9, 2, 'Y1'), --I
(9, 4, 'Y2'), --I
(10, 2, 'Y1'), --I
(10, 4, 'Y2'), --I
(10, 5, 'Z'), --S
(11, 0, 'X'), --P
(11, 2, 'Y1'), --I
(11, 4, 'Y2'), --I
(11, 5, 'Z') --S
) as T(GroupID, Position, Value)
order by GroupID, Position
;with cte (
ID,
GroupID,
LeftString,
Value,
RightString,
Position
) as (
select
ID,
GroupID,
LeftString,
Value,
RightString,
Position
from (
select
row_number() over (partition by GroupID order by ID) as RowNumber,
ID,
GroupID,
cast(left(@String, Position) as varchar(200)) as LeftString,
Value,
cast(right(@String, @StringLen - Position) as varchar(200)) as RightString,
Position
from @Chars
) as C
where RowNumber = 1
union all
select
vc.ID,
vc.GroupID,
cast(left(RightString, vc.Position - cte.Position) as varchar(200)) as LeftString,
vc.Value,
cast(right(RightString, @StringLen - vc.Position) as varchar(200)) as RightString,
vc.Position
from @Chars vc
join cte cte
on cte.GroupID = vc.GroupID
and cte.ID + 1 = vc.ID
)
select
GroupID,
case
when LSLenSumMax < @StringLen
then NewString + RightString
else NewString
end as NewString
from (
select
GroupID,
max(LSLenSum) as LSLenSumMax,
RightString,
stuff((
select
LeftString + Value
from cte cte
where cte.GroupID = cteLR.GroupID
for xml path(''), type
).value('(./text())[1]', 'varchar(max)'), 1, 0, '') as NewString
from (
select
GroupID,
(select sum(len(LeftString)) from cte cteL where cteL.groupID = cte.groupID) as LSLenSum,
(select top 1 RightString from cte cteR where cteR.groupID = cte.groupID order by cteR.ID desc) as RightString
from cte cte
) as cteLR
group by
GroupID,
RightString
) as C
order by GroupID发布于 2016-06-27 20:27:38
您可以实现自定义聚合函数..。或者尝试如下:递归标量函数:
CREATE FUNCTION dbo.GetPrefixTo (@GroupID INT, @Position INT, @String CHAR(200))
RETURNS Char(200)
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @str CHAR(200) = NULL
DECLARE @beforePosition INT = 0
IF (SELECT COUNT(*) FROM Chars WHERE GroupID = @GroupID AND Position < @Position) > 0
BEGIN
SELECT @beforePosition = MAX(Position) FROM chars WHERE GroupID = @GroupID AND Position < @Position
select @str = RTRIM(dbo.GetPrefixTo(@GroupID, @beforePosition, substring(@String, 1, @Position))) +
+ RTrim(Value) + substring(@String, @Position + 1, len(@string) + 1)
FROM Chars WHERE GroupID = @GroupID AND Position = @Position
END
ELSE
SELECT @str = substring(@String, 1, @Position) + RTrim(Value) + substring(@String, @Position + 1, len(@string) + 1) FROM Chars
WHERE GroupID = @GroupID AND Position = @Position
RETURN @str
END并按GroupID和aggregate max(位置)分组:
SELECT groupID, max(Position)
, dbo.GetPrefixTo(groupID, max(Position), 'abcde')
FROM Chars
GROUP BY GroupID其结果是:
1 0 Xabcde
2 2 abYcde
3 5 abcdeZ
4 2 XabYcde
5 5 abYcdeZ
6 5 XabcdeZ
7 5 XabYcdeZ
8 4 abY1cdY2e
9 4 XabY1cdY2e
10 5 abY1cdY2eZ
11 5 XabY1cdY2eZ ========================================================================
https://stackoverflow.com/questions/38058069
复制相似问题