【问题标题】:Reverse the order of words in T-SQL反转 T-SQL 中的单词顺序
【发布时间】:2011-12-02 20:16:20
【问题描述】:

我想知道如何(如果可能的话)反转从 T-SQL 字符串 (varchar) 返回的 单词 的顺序。

我知道 T-SQL REVERSE 函数。但该函数也会反转单词中的字母,例如:

输入 > We want to tell you we all love StackOverflow
输出>wolfrevOkcatS evol lla ew uoy llet ot tnaw eW

我想在 T-SQL 中实际实现以下目标:

输入 > We want to tell you we all love StackOverflow
输出>Stackoverflow love all we you tell to want We

我在任何地方发现的唯一稍微相似的问题是this one,但是这包括拆分逗号分隔的字符串,我不需要这样做。

我确信有一种方法可以实现上述目的,即使它是自定义函数或 SQL-CLR 函数。


我设法使用以下方法拆分字符串:

-- Create a space delimited string for testing
declare @str varchar(max)
select @str = 'We want to tell you we all love StackOverflow'
-- XML tag the string by replacing spaces with </x><x> tags
declare @xml xml
select @xml = cast('<x><![CDATA['+ replace(@str,' ',']]></x><x><![CDATA[') + ']]></x>' as xml)
-- Finally select values from nodes <x> and trim at the same time
select ltrim(rtrim(mynode.value('.[1]', 'nvarchar(50)'))) as Code
from (select @xml doc) xx
cross apply doc.nodes('/x') (mynode)

现在的问题是试图以向后 (DESC) 的顺序将它们全部拼凑成一个字符串。

【问题讨论】:

  • 我认为您可以使用您引用的问题 - 但使用“”作为分隔符而不是逗号。一旦你有了拆分列表,就很容易操纵顺序。
  • 为什么不使用您已经找到的解决方案?这是一个逗号分隔的字符串,但你的是空格分隔的,所以唯一的区别是分隔符(忽略标点符号问题)。更一般地说,这类问题是许多语言中常见的学习或教程练习,因此您可能会通过尝试自己解决(在 TSQL 或 CLR 过程中)然后在您有特定编码时发布来从这项任务中获得更多收益问题,你可以显示你已经尝试过的代码。
  • 查看此问题以了解 SPLIT() 函数问题的各种解决方案:stackoverflow.com/questions/2647/split-string-in-sql
  • 我没有使用我引用的问题的原因是因为我读到生产环境中的游标是一个坏主意?我确定必须有一个比那里发布的方式更简单的解决方案?
  • @Aracas:游标名声不好,因为大多数人使用它们来循环 SQL 结果集,做的事情可以通过基于集合的解决方案更好地解决。但我认为仅在少数内存变量上使用游标没有任何问题。

标签: sql-server sql-server-2005 tsql sqlclr


【解决方案1】:

您可以在 SQL 中创建一个小函数来反转字符串,如下所示:

DECLARE @source VARCHAR(MAX)
DECLARE @dest VARCHAR(MAX)
DECLARE @lenght INT

SET @source = 'We want to tell you we all love StackOverflow'
SET @dest = ''

WHILE LEN(@source) > 0
BEGIN
    IF CHARINDEX(' ', @source) > 0
    BEGIN
        SET @dest = SUBSTRING(@source,0,CHARINDEX(' ', @source)) + ' ' + @dest
        SET @source = LTRIM(RTRIM(SUBSTRING(@source,CHARINDEX(' ', @source)+1,LEN(@source))))
    END
    ELSE
    BEGIN
        SET @dest = @source + ' ' + @dest
        SET @source = ''
    END
END
SELECT @dest

【讨论】:

    【解决方案2】:

    首先,这是基于 CLR 的解决方案会更好的情况之一,尤其是在性能方面(该解决方案将始终使用迭代和字符串操作)。

    这里有几行 C# 实现了结果,虽然它没有你需要的 SQL-CLR 代码:

    string original = "We want to tell you we all love StackOverflow";
    string[] parts = original.Split(' ');
    
    StringBuilder reversedString = new StringBuilder();
    for (int i = parts.Length - 1; i >= 0; i--)
    {
        reversedString.Append(parts[i]);
        reversedString.Append(" ");
    }
    
    string result = reversedString.ToString();
    

    使用 LINQ 会更短,但我想我会保持简单。对于 T-SQL 解决方案,您可以从前面提到的 split post 中 vzczc 的帖子中的 splitString 函数开始。

    基于此,您可以这样做:

    DECLARE @ReverseString VARCHAR(MAX)
    
    SET @ReverseString = ''
    
    SELECT @ReverseString = @ReverseString + s + ' ' 
    FROM
    (
        SELECT s, zeroBasedOccurance
        FROM dbo.SplitString('We want to tell you we all love StackOverflow', ' ')
    ) A
    ORDER BY A.zeroBasedOccurance DESC
    
    SELECT @ReverseString
    

    这应该可行,但它用于将字符串连接在一起的方法未记录在案,并且在 SQL Server 的未来版本中可能无法正常工作。与 CLR 解决方案相比,它的性能可能也很差,所以如果你有时间实现它,那就去做吧。

    【讨论】:

      【解决方案3】:
      declare @str varchar(100),
              @result varchar(100)
      
      set @str = 'We want to tell you we all love StackOverflow'
      
      ;with cte as 
      (
      select 1 pos_from, charindex(' ', @str) + 1 pos_to
      union all
      select pos_to, charindex(' ', @str + ' ', pos_to) + 1
      from cte
      where pos_to <= len(@str)
      )
      select @result = coalesce( @result + ' ', '') +substring(@str, pos_from, pos_to - pos_from - 1) 
      from cte
      order by pos_to desc
      
      select @result
      

      【讨论】:

      • 解释一下。请通过editing (changing) your answer 回复,而不是在 cmets 中(without "Edit:"、"Update:" 或类似的 - 答案应该看起来像是今天写的)。
      【解决方案4】:

      SQL Server 的原生 XML 支持为这些问题提供了一些强大(且简洁)的解决方案:

      DECLARE @xml XML, @source VARCHAR(MAX), @delimiter VARCHAR(10)
      
      SET @source = 'We want to tell you we all love StackOverflow'
      SET @delimiter = ' '
      SET @xml = CAST(('<X>' + REPLACE(@source, @delimiter, '</X><X>') + '</X>') AS XML)
      
      SELECT STUFF((SELECT @delimiter + C.value('.', 'VARCHAR(50)')
                      FROM @xml.nodes('X') AS X(C)
                     ORDER BY ROW_NUMBER() OVER (ORDER BY (SELECT 0)) DESC
                       FOR XML PATH('')), 1, 1, '')
      

      【讨论】:

        【解决方案5】:

        由于接受的答案不是一个函数,这里是一个。

        我还删除了接受答案产生的额外无用空间

        CREATE FUNCTION [dbo].[fn_ReverseWords] (@input VARCHAR(MAX))
        RETURNS VARCHAR(MAX)
        BEGIN
            DECLARE @output VARCHAR(MAX)
            SET @output = ''
            WHILE LEN(@input) > 0
            BEGIN
                IF CHARINDEX(' ', @input) > 0
                BEGIN
                    SET @output = SUBSTRING(@input,0,CHARINDEX(' ', @input)) + ' ' + @output
                    SET @input = LTRIM(RTRIM(SUBSTRING(@input,CHARINDEX(' ', @input) + 1,LEN(@input))))
                END
                ELSE
                BEGIN
                    SET @output = @input + ' ' + @output
                    SET @input = ''
                END
            END
            RETURN substring(@output,0, len(@output)) -- remove useless space
        END
        

        【讨论】:

        • 谢谢约翰。注意,需要在len(@output)后面加上+1,否则会截掉一个字母
        猜你喜欢
        • 2010-11-03
        • 2011-11-07
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多