繁体   English   中英

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

[英]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组合将它们连接回来,如下所示。

我建议您尽早在此处阅读有关 Tally 表的信息

演示链接也在这里

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM