如何逐字反转列中的字符串?

How to reverse string in column a word by word?

我有一个 table,其中 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

你能帮我在单个查询中实现这个吗?

首先所有之前的评论都是正确的,特别是这是一个数据模型问题。这是一个非常笨拙的解决方案。我提供它是因为您只有 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

Aditi 您可以使用 Tally table 找到所有 _ 然后使用 STUFF + FOR XML PATH 组合将它们重新加入,如下所示。

我建议您尽早阅读 Tally tables here

演示 link 也是 here

--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

您需要使用拆分器拆分存储的字符串,即 returns 子字符串和每个子字符串的位置。之后,您可以轻松构建所需的输出。

如果您使用 SQL Server 2017+,您可以尝试 JSON-based 方法。您需要将每个字符串转换为有效的 JSON 数组(例如 P1_P10_P45_P20 转换为 ["'P1","P10","P45","P20"]),将此数组解析为 table 和 OPENJSON() 并加入具有 STRING_AGG() 的行以生成预期的输出:

Table:

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