如何逐字反转列中的字符串?
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
我有一个 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