在变量中连接有序String_Split的结果

时间:2016-06-30 17:20:15

标签: sql-server tsql sql-order-by

在我使用的SqlServer数据库中,数据库名称类似于StackExchange.Audio.Meta,或StackExchange.AudioStackOverflow。纯粹运气,这也是一个网站的网址。我只需将它分成点并反转它:meta.audio.stackexchange。添加http://.com并完成了我的工作。显然Stackoverflow不需要任何逆转。

使用SqlServer 2016 string_split函数,我可以轻松拆分并重新排序其结果:

select value
from string_split(db_name(),'.')
order by row_number() over( order by (select 1)) desc

这给了我

|  Value        |
-----------------
| Meta          |
| Audio         |
| StackExchange |

由于我需要在变量中使用url,我希望使用此answer将其连接起来,所以我的尝试看起来像这样:

declare @revname nvarchar(150)
select @revname = coalesce(@revname +'.','')  + value
from string_split(db_name(),'.')
order by row_number() over( order by (select 1)) desc

然而,这只会返回最后一个值StackExchange。我已经注意到该答案的警告,这个技巧仅适用于某些执行计划,如here所述。

问题似乎是由order by子句引起的。没有它,我得到所有的价值,但然后是错误的顺序。我尝试添加ltrimrtrim函数,如Microsoft文章和子查询中所建议的那样但到目前为止没有运气。

有没有办法可以轻推Sql Server 2016查询引擎来连接变量中string_split的有序结果?

我知道我可以使用for XML甚至是一个简单的光标来获得我需要的结果,但我还是不想放弃这个优雅的解决方案。

由于我在Stack Exchange Data Explorer上运行此功能,因此我无法使用这些功能,因为我们缺乏创建这些功能的权限。我可以做存储过程,但我希望我可以逃避它们。

我准备了SEDE Query来试验。期望的数据库名称要么没有点,也就是StackOverflow,有1个点:StackOverflow.Meta或2个点,`StackExchange.Audio.Meta,完整的数据库列表是here

5 个答案:

答案 0 :(得分:3)

我认为你过于复杂。您可以使用PARSENAME

SELECT 'http://' + PARSENAME(db_name(),1) + 
       ISNULL('.' + PARSENAME(db_name(),2),'') + ISNULL('.'+PARSENAME(db_name(),3),'') 
       + '.com'

答案 1 :(得分:1)

这正是我在分割功能中使用演示序列(PS)的原因。人们经常嘲笑使用UDF来处理这些项目,但通常会一次性解析一些东西供以后消费。

Select * from [dbo].[udf-Str-Parse]('meta.audio.stackexchange','.')

返回

Key_PS  Key_Value
1       meta
2       audio
3       stackexchange

UDF

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('meta.audio.stackexchange','.')
--       Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--       Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')

Returns @ReturnTable Table (Key_PS int IDENTITY(1,1) NOT NULL , Key_Value varchar(max))

As

Begin
   Declare @intPos int,@SubStr varchar(max)
   Set @IntPos = CharIndex(@delimeter, @String)
   Set @String = Replace(@String,@delimeter+@delimeter,@delimeter)
   While @IntPos > 0
      Begin
         Set @SubStr = Substring(@String, 0, @IntPos)
         Insert into @ReturnTable (Key_Value) values (@SubStr)
         Set @String = Replace(@String, @SubStr + @delimeter, '')
         Set @IntPos = CharIndex(@delimeter, @String)
      End
   Insert into @ReturnTable (Key_Value) values (@String)
   Return 
End

答案 2 :(得分:1)

可能不太优雅的解决方案,但它只需要几行,并且可以使用任意数量的点。

;with cte as (--build xml
  select 1 num, cast('<str><s>'+replace(db_name(),'.','</s><s>')+'</s></str>' as xml) str
)
,x as (--make table from xml
    select row_number() over(order by num) rn, --add numbers to sort later
       t.v.value('.[1]','varchar(50)') s
    from cte cross apply cte.str.nodes('str/s') t(v)
)
--combine into string
select STUFF((SELECT '.' + s AS [text()]
            FROM x
            order by rn desc --in reverse order
            FOR XML PATH('')
            ), 1, 1, '' ) name

答案 3 :(得分:1)

  

有没有办法可以轻推Sql Server 2016查询引擎来连接变量中string_split的有序结果?

您可以使用partail1

CONCAT

逆转是通过DECLARE @URL NVARCHAR(MAX) SELECT @URL = CONCAT(value, '.', @URL) FROM STRING_SPLIT(DB_NAME(), '.') SET @URL = CONCAT('http://', LOWER(@URL), 'com'); 的参数顺序完成的。 Here's an example

它将CONCAT更改为StackExchange.Garage.Meta

这通常可用于拆分和反转字符串,但请注意它确实留下了尾随分隔符。我相信你可以在那里添加一些逻辑或http://meta.garage.stackexchange.com以使其不会发生。

另请注意,vNext将添加STRING_AGG

答案 4 :(得分:1)

要回答这个XY问题的'X',并解决HTTPS交换机(尤其是Meta网站)和其他一些网站名称更改,我写了以下SEDE query,它输出所有网站名称network site list上使用的格式。

SELECT name,
  LOWER('https://' +
    IIF(PATINDEX('%.Mathoverflow%', name) > 0,
    IIF(PATINDEX('%.Meta', name) > 0, 'meta.mathoverflow.net', 'mathoverflow.net'),
      IIF(PATINDEX('%.Ubuntu%', name) > 0,
      IIF(PATINDEX('%.Meta', name) > 0, 'meta.askubuntu.com', 'askubuntu.com'),
        IIF(PATINDEX('StackExchange.%', name) > 0,
          CASE SUBSTRING(name, 15, 200)
          WHEN 'Audio' THEN 'video'
          WHEN 'Audio.Meta' THEN 'video.meta'
          WHEN 'Beer' THEN 'alcohol'
          WHEN 'Beer.Meta' THEN 'alcohol.meta'
          WHEN 'CogSci' THEN 'psychology'
          WHEN 'CogSci.Meta' THEN 'psychology.meta'
          WHEN 'Garage' THEN 'mechanics'
          WHEN 'Garage.Meta' THEN 'mechanics.meta'
          WHEN 'Health' THEN 'medicalsciences'
          WHEN 'Health.Meta' THEN 'medicalsciences.meta'
          WHEN 'Moderators' THEN 'communitybuilding'
          WHEN 'Moderators.Meta' THEN 'communitybuilding.meta'
          WHEN 'Photography' THEN 'photo'
          WHEN 'Photography.Meta' THEN 'photo.meta'
          WHEN 'Programmers' THEN 'softwareengineering'
          WHEN 'Programmers.Meta' THEN 'softwareengineering.meta'
          WHEN 'Vegetarian' THEN 'vegetarianism'
          WHEN 'Vegetarian.Meta' THEN 'vegetarianism.meta'
          WHEN 'Writers' THEN 'writing'
          WHEN 'Writers.Meta' THEN 'writing.meta'
          ELSE SUBSTRING(name, 15, 200)
          END + '.stackexchange.com',
          IIF(PATINDEX('StackOverflow.%', name) > 0,
            CASE SUBSTRING(name, 15, 200)
            WHEN 'Br' THEN 'pt'
            WHEN 'Br.Meta' THEN 'pt.meta'
            ELSE SUBSTRING(name, 15, 200)
            END + '.stackoverflow.com',
            IIF(PATINDEX('%.Meta', name) > 0,
              'meta.' + SUBSTRING(name, 0, PATINDEX('%.Meta', name)) + '.com',
              name + '.com'
            )
          )
        )
      )
    ) + '/'
  )
  FROM sys.databases WHERE database_id > 5