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

问题描述 投票:3回答:5

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

使用Sql Server 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条款引起的。没有它,我得到所有的价值,但然后是错误的顺序。我试图添加ltrimand rtrim函数,如微软文章和子查询中所建议,但到目前为止没有运气。

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

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

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

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

sql-server tsql sql-order-by
5个回答
3
投票

我觉得你过于复杂了。你可以使用PARSENAME

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

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

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

1
投票

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

你可以使用CONCAT

DECLARE @URL NVARCHAR(MAX)
SELECT @URL = CONCAT(value, '.', @URL) FROM STRING_SPLIT(DB_NAME(), '.')
SET @URL = CONCAT('http://', LOWER(@URL), 'com');

通过CONCAT的参数顺序完成逆转。 Here's an example

它将StackExchange.Garage.Meta改为http://meta.garage.stackexchange.com

这通常可用于拆分和反转字符串,但请注意它确实留下了尾随分隔符。我相信你可以在那里添加一些逻辑或COALESCE来实现这一点。

另请注意,vNext将添加STRING_AGG


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
© www.soinside.com 2019 - 2024. All rights reserved.