【问题标题】:Retrieve String Between Two Delimiters for Multiple Occurences SQL Server检索多次出现的两个分隔符之间的字符串 SQL Server
【发布时间】:2015-10-21 22:15:46
【问题描述】:

如何从下面得到结果集为 TESTING1,TESTING2

DECLARE @MyString varchar(256) = '$I10~TESTING1$XYZ$I10~TESTING2$~'

基本上我需要得到介于 $I10~ 和 $ 之间的所有子字符串

【问题讨论】:

  • 谷歌:“SQL Server 拆分”

标签: sql-server substring


【解决方案1】:

查看内联 cmets 了解正在发生的事情的概述:

DECLARE @MyString varchar(256) = '$I10~TESTING1$XYZ$I10~TESTING2$~'
, @pre char(5) = '$I10~' --this appears before the string we want
, @post char(1) = '$' --this appears after it
select 
--take part of
substring( 
    --the input string
    @MyString     
    --starting from the first pre-delimiter (but add on the length of the delimeter so we exclude the delimeter itself)
    ,charindex(@pre,@MyString) + len(@pre) 
    --and ending at the first post-delimiter to appear after the first pre-delimeter
    , charindex(@post,@MyString,charindex(@pre,@MyString) + len(@pre)) - (charindex(@pre,@MyString) + len(@pre))
) 
,
--for the second result do the same as above
substring(
    @MyString
    --only now we're looking for the second pre-delimiter (aka the first after the first)
    ,charindex(@pre,@MyString,charindex(@pre,@MyString) + len(@pre)) + len(@pre)
    --and the second post-delimiter
    ,charindex(@post,@MyString,charindex(@pre,@MyString,charindex(@pre,@MyString) + len(@pre)) + len(@pre)) - (charindex(@pre,@MyString,charindex(@pre,@MyString) + len(@pre)) + len(@pre))
) 

注意:这假设前定界符不会出现在前后定界符之间;如果这样做可能会令人困惑/我们需要确定所需的行为。

substring(@stringToBreakApart, @indexOfFirstCharacterInSubstring, @lengthOfResultingString) - 返回一段原始字符串。

charindex(@stringToFind, @stringToSearch, @indexOfFirstCharacterToLookAt) - 返回给定字符串中给定子字符串的第一个字符的索引。

len(@stringToAnalyze) - 返回给定字符串的字符数(长度)。

更新

每个 cmets,您可以通过以下方式返回单个列,该列在分隔符上拆分字符串(忽略不在前后之间的任何内容),然后将结果连接起来形成一个逗号分隔的字段。

DECLARE @MyString varchar(256) = '$I10~TESTING1$XYZ$I10~TESTING2$~$I10~TESTING3$...'
, @pre char(5) = '$I10~' --this appears before the string we want
, @post char(1) = '$' --this appears after it
, @newDelim char(1) = ','
;with cte(indx, firstCharIndex, lastCharIndex) as 
(
    select 0 
    , charindex(@pre,@MyString) + len(@pre) 
    , charindex(@post,@MyString,charindex(@pre,@MyString) + len(@pre)) 

    union all

    select indx + 1
    , charindex(@pre,@MyString, lastCharIndex + len(@post)) + len(@pre) 
    , charindex(@post,@MyString,charindex(@pre,@MyString, lastCharIndex + len(@post)) + len(@pre)) 
    from cte
    where charindex(@pre,@MyString, lastCharIndex + len(@post)) > 0
)
, cte2 (substr, indx ) as 
(
    select cast(substring(@MyString, firstCharIndex, lastCharIndex - firstCharIndex) as nvarchar(max)) 
    , indx
    from cte 
    where indx = (select max(indx) from cte)

    union all

    select substring(@MyString, firstCharIndex, lastCharIndex - firstCharIndex) + @newDelim + cte2.substr
    , cte.indx
    from cte
    inner join cte2 on cte2.indx = cte.indx + 1 

)
select * from cte2 where indx = 0

【讨论】:

  • 谢谢....这会起作用,但是如果我们有 10 个值,例如 (TESTING1,TESTING2...TESTING10) 存在于分隔符 '$I10~' 和 '$' 之间,我们有使用子字符串 10 次。有没有办法让我们动态地做到这一点
  • 是的...见stackoverflow.com/questions/2647/…。但是,如果您有多个结果,则会遇到问题; SQL 可以很容易地返回动态的行数,但更难返回动态的列数......所以请考虑您希望输出如何工作(即您是否希望每个源行有多个行,是否要限制列数达到某个上限(使用空值填充不需要所有列的字段),或者您是否想在拆分后再次加入结果,仅使用更简单的分隔符..
  • 我希望一列中的结果为 TESTING1,TESTING2,TESTING3...TESTINGN... 我正在使用路径下方的函数 berezniker.com/content/pages/sql/microsoft-sql-server/… 但这只会处理字符串中的一次出现。 .. 我们可以调整这个函数来处理多个事件
  • @JohnLBevan 更新后的答案给出了模式的第一次出现,比如 123|abc adf *456|asdfaf 是输入字符串,开始字符是 *,结束字符是 |,查询返回 123 和不是 123 和 456
  • 谢谢@RamVenkat;好地方...有时间我会回来修改。
猜你喜欢
  • 1970-01-01
  • 2019-04-05
  • 1970-01-01
  • 2019-04-02
  • 2018-06-14
  • 2012-04-27
  • 1970-01-01
  • 2014-12-08
  • 1970-01-01
相关资源
最近更新 更多