[英]How to reverse string in column a word by word?
我有一个带有varchar(50)
列'Relation'
的表,其中包含超过 1000 行的数据,例如:
P1_P10_P45_P20
P1_P14_P5_P22
P1_P3
P3_P4_P5_P2_P100_P2_P1
我希望输出具有相反的顺序:
P20_P45_P10_P1
P22_P5_P14_P1
P3_P1
P1_P2_P100_P2_P5_P4_P3
你能帮我在单个查询中实现这个吗?
Aditi,您可以使用 Tally 表查找所有 _,然后使用 S TUFF + FOR XML PATH组合将它们连接回来,如下所示。
演示链接也在这里
--create table yourtable(Relation nvarchar(50));
--insert into yourtable values
-- ('P1_P14_P5_P22'),
-- ('P1_P3'),
-- ('P3_P4_P5_P2_P100_P2_P1'), ('P1_P3'),
-- ('P3_P4_P5_P2_P100_P2_P1');
;WITH Tally AS (
SELECT 1 as Num
UNION ALL
SELECT Num + 1 FROM Tally WHERE Num < 51
)
,
InputSet AS
(
select *, RN=row_number() over (order by (select 1)) from yourtable
)
,TempSet AS
(
SELECT
Relation,
Num,
RN,
partBetweenUnderscore = SUBSTRING(Relation, Num, ISNULL(LEAD(Num) OVER (Partition by RN ORDER BY Num ASC),LEN('_'+Relation)+1)-Num-1)
FROM
(
SELECT *
FROM InputSet CROSS JOIN Tally
WHERE CHARINDEX('_','_'+Relation,Num)=Num
)T
)
SELECT
Relation,
NewRelation = STUFF(
(SELECT '_' + T1.partBetweenUnderscore FROM TempSet T1 WHERE T1.RN=T2.RN ORDER BY T1.Num DESC FOR XML PATH ('')
),1,1,'')
FROM TempSet T2
GROUP BY RN, Relation
您需要使用拆分器拆分存储的字符串,该拆分器返回子字符串和每个子字符串的位置。 之后,您可以轻松构建所需的输出。
如果您使用 SQL Server 2017+,您可以尝试基于 JSON 的方法。 您需要将每个字符串转换为有效的 JSON 数组(例如P1_P10_P45_P20
到["'P1","P10","P45","P20"]
),将此数组解析为带有OPENJSON()
的表并加入行使用STRING_AGG()
生成预期输出:
桌子:
CREATE TABLE Data (Relation varchar(50))
INSERT INTO Data (Relation)
VALUES
('P1_P10_P45_P20'),
('P1_P14_P5_P22'),
('P1_P3'),
('P3_P4_P5_P2_P100_P2_P1')
陈述:
SELECT c.Relation
FROM Data d
OUTER APPLY (
SELECT STRING_AGG([value], '_') WITHIN GROUP (ORDER BY CONVERT(int, [key]) DESC)
FROM OPENJSON(CONCAT('["', REPLACE(d.Relation, '_', '","'), '"]'))
) c (Relation)
结果:
Relation
----------------------
P20_P45_P10_P1
P22_P5_P14_P1
P3_P1
P1_P2_P100_P2_P5_P4_P3
首先,之前的所有评论都是正确的,尤其是这是一个数据模型问题。 这是一个非常笨拙的解决方案。 我提供它是因为您只有 1000 条记录。 这效率不高,也不会扩大规模。 以下适用于 MS SQL Server 2017。
Drop table if exists Relation
create table Relation (Relation varchar(50))
INSERT INTO Relation (Relation)
VALUES
('P1_P10_P45_P20'),
('P1_P14_P5_P22'),
('P1_P3'),
('P3_P4_P5_P2_P100_P2_P1');
DROP TABLE IF EXISTS Rev
create table Rev (Relation varchar(50), Rev varchar(50))
DROP TABLE IF EXISTS Z
create table Z (token varchar(50))
declare @Reverse varchar(50)
set @Reverse = ''
declare @token varchar(50)
declare @Relation varchar(50)
declare cur cursor for select * from Relation
open cur
fetch next from cur into @Relation
while @@FETCH_STATUS = 0
begin
with T(Relation, starts, pos) as (
select @Relation, 1, charindex('_', @Relation)
union all
select @Relation, pos + 1, charindex('_', @Relation, pos + 1)
from T
where pos > 0)
insert into Z select substring(@Relation, starts, case when pos > 0 then pos - starts else len(@Relation) end) token
from T
declare cur2 cursor for select token from Z
open cur2
fetch next from cur2 into @token
while @@FETCH_STATUS = 0
begin
set @Reverse = @token + '_' + @Reverse
fetch next from cur2 into @token
end
close cur2
deallocate cur2
set @Reverse = (select left(@Reverse,len(@Reverse)-1))
insert into Rev select @Relation, @Reverse
set @Reverse = ''
delete Z
fetch next from cur into @Relation
end;
close cur
deallocate cur
select * from Rev
SELECT @@version
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.