反转SQL中单词的顺序

时间:2011-10-07 08:37:00

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

我想知道如何(如果可能的话)颠倒从TSQL字符串(varchar)返回的单词的顺序。

我知道TSQL REVERSE函数,但也会反转单词中的字母,例如:

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

我想在TSQL中实际实现以下目标:

输入> 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)顺序排列的字符串。

5 个答案:

答案 0 :(得分:6)

您可以在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

答案 1 :(得分: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解决方案相比,它可能也会表现得非常糟糕,所以如果你有时间实现它,那就这样做。

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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, '')

答案 4 :(得分:1)

Since the accepted answer is not a function, here is one.

Also I removed the extra useless space generated by the accepted answer

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