优化的备用代码,用于在SQL SERVER中逐字反向输入字符串的功能

时间:2018-07-02 10:07:51

标签: sql sql-server tsql

alter FUNCTION FlipName(@input VARCHAR(250))
RETURNS VARCHAR(250)

AS BEGIN

DECLARE @i int ,@add varchar(255)
set @i=1
set @add=''
declare @work varchar(250)
set @work=''
WHILE @i <= len(@input)
BEGIN
  declare @pivot varchar(255)
  set @pivot=SUBSTRING(@input,@i,1)
  while @pivot <>' '
  begin
     set @add=@add+@pivot
     set @i=@i+1
     set @pivot=SUBSTRING(@input,@i,1)
  end

  set @work=@add+' '+@work 
  set @add=''

  SET @i = @i + 1

END
return @work
END
  

示例输入:我叫Jarvis

     

示例输出:Jarvis是我的名字

我正在寻找对此的更短,更简洁的替代代码,因为这里的嵌套循环是性能的杀手

我正在寻找一种可能没有循环的更好的解决方法

请为您的解决方案提供一个简洁的说明,说明其效果如何。

提前谢谢

5 个答案:

答案 0 :(得分:3)

T-SQL并不是字符串处理的最佳解决方案。但这完全可以做到没有循环(SQL Server 2017 +):

DECLARE @s NVARCHAR(MAX) = N'My name is Jarvis';

SELECT @s, STRING_AGG(value, ' ') WITHIN GROUP(ORDER BY rn DESC)
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY 1/0)AS rn
      FROM STRING_SPLIT(REPLACE(@s, ' ', '.'), '.'))s;

DBFiddle Demo

答案 1 :(得分:2)

考虑到这里的序数位置很重要(STRING_SPLIT不会返回),并且STRING_SPLITSTRING_AGG是最近添加的函数,因此可以使用{{3} }和FOR XML PATH。这意味着顺序得到保证(因为delimitedsplit8k返回顺序位置),这意味着您不需要SQL Server 2017:

USE Sandbox;
GO

CREATE FUNCTION dbo.ReverseString_fn (@input varchar(255))
RETURNS table AS
RETURN

    SELECT STUFF((SELECT ' ' + DS.Item
                  FROM dbo.DelimitedSplit8K(@input,' ') DS
                  ORDER BY DS.ItemNumber DESC
                  FOR XML PATH('')),1,1,'') AS ReverseString;
GO

WITH VTE AS (
    SELECT 'My name is Jarvis' AS String)
SELECT *
FROM VTE V
     CROSS APPLY dbo.ReverseString_fn(V.String) RS;
GO

DROP FUNCTION dbo.ReverseString_fn;

答案 2 :(得分:1)

还有另一种...以下方法是完全内联的,并结合XML通过位置获取元素的能力而使用了即时计数表:

DECLARE @input VARCHAR(100)='My name is Jarvis';

WITH Casted(inputXml) AS
(
    SELECT CAST('<x>' + REPLACE((SELECT @input AS [*] FOR XML PATH('')),' ','</x><x>') + '</x>' AS XML)
)
,Tally(Nmbr) AS
(
    SELECT TOP(SELECT inputXml.value('count(/x)','int') FROM Casted) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values
)
SELECT STUFF(
(
    SELECT ' ' + c.inputXml.value('(/x[sql:column("t.Nmbr")]/text())[1]','varchar(100)')
    FROM Tally t
    CROSS JOIN Casted c
    ORDER BY t.Nmbr DESC
    FOR XML PATH(''),TYPE).value('.','varchar(max)'
),1,1,'');

答案 3 :(得分:0)

我不建议在后端这样做。 但是要解决( SQL Server 2016以下)的问题,您可以使用以下代码。 您可以使用以下代码创建函数,然后在表行上调用它。

DECLARE @VAL VARCHAR(MAX) ='My name is Jarvis', @NEW_VAL VARCHAR(MAX)='';

SELECT @VAL = '<M>'+ REPLACE(@VAL, ' ','</M><M>')+'</M>';

SELECT @NEW_VAL = @NEW_VAL+ ' ' + NEW_TEXT FROM ( 
SELECT ROW_NUMBER() OVER(ORDER BY(SELECT 1)) SNO, 
 splt.x.value('.','varchar(100)') NEW_TEXT FROM (
SELECT CAST(@VAL AS XML) AS DATA
)AS A
CROSS APPLY DATA.nodes('/M') as splt(x)
)B
ORDER BY SNO DESC;

SELECT @NEW_VAL

结果:

 Jarvis is name My

答案 4 :(得分:-1)

如果您想逐个单词地反转字符串,则可以使用以下优化代码。

CREATE FUNCTION [dbo].[fn_ReverseWordsInSentence]
(
    @ip VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)

BEGIN
    DECLARE @op VARCHAR(MAX)
    SET @op = ''
    DECLARE @Lenght INT

    WHILE LEN(@ip) > 0
    BEGIN
        IF CHARINDEX(' ', @ip) > 0
        BEGIN
        SET @op = SUBSTRING(@ip,0,CHARINDEX(' ', @ip)) + ' ' + @op
        SET @ip = LTRIM(RTRIM(SUBSTRING(@ip,CHARINDEX(' ', @ip) + 1,LEN(@ip))))
    END
    ELSE
        BEGIN
        SET @op = @ip + ' ' + @op
        SET @ip = ''
        END
    END
RETURN @op
END

您可以使用您提到的输入字符串执行此功能,如下所示。

SELECT [dbo].[fn_ReverseWordsInSentence] ('My name is Jarvis')

这将返回以下字符串作为输出。

“贾维斯是我的名字”

如果只想逐个字符地反转整个字符串,则可以在内置的反向字符串函数中使用Sql Server。

DECLARE @test varchar(250) = 'My name is Jarvis'

SELECT reverse(@test)

这将返回“ sivraJ si eman yM”作为输出。