【问题标题】:How to extract a string between two of the SAME delimiters T-SQL?如何在两个相同的分隔符 T-SQL 之间提取字符串?
【发布时间】:2021-09-02 10:24:54
【问题描述】:

我想从具有多个相同分隔符的值中提取部分字符串。

这是我正在处理的数据示例(这些文件路径可能会更长,具体取决于文件的深度):

文件路径:

问:\12345\downloads\randomfilename.png

问:\123_4566\downloads\randomfilename.pdf

Q:\CCCMUD\downloads\randomfilename.mp4

我想将每一行的前两个定界符 (\) 之间的部分字符串提取到一个新列中,例如

12345

123_4566

CCCMUD

我知道我需要使用 SUBSTRING 和 CHARINDEX,但我不确定如何使用。我将不胜感激任何帮助。谢谢。

【问题讨论】:

  • 根据问题指南,请展示您的尝试并告诉我们您发现了什么(在本网站或其他地方)以及为什么它不能满足您的需求。
  • 请提供足够的代码,以便其他人更好地理解或重现问题。
  • 感谢您的 cmets!我相信下面的“Salman A”已经正确回答了这个问题

标签: sql sql-server string tsql


【解决方案1】:

使用CHAR_INDEX 两次:

SELECT *, SUBSTRING(path, pos1 + 1, pos2 - pos1 - 1)
FROM tests
CROSS APPLY (SELECT NULLIF(CHARINDEX('\', path), 0)) AS ca1(pos1)
CROSS APPLY (SELECT NULLIF(CHARINDEX('\', path, pos1 + 1), 0)) AS ca2(pos2)

-- NULLIF is used to convert 0 value (character not found) to NULL

Test on db<>fiddle

【讨论】:

  • 非常感谢 - 这正是我想要的! :-)
【解决方案2】:

在所有示例中,第一个 \ 位于字符串中的第 3 个字符处。如果是这样,那么您可以简单地使用:

select v.*,
       substring(filepath, 4, charindex('\', filepath, 4) - 4)
from (values ('Q:\123_4566\downloads\randomfilename.pdf')) v(filepath)

【讨论】:

    【解决方案3】:
    DECLARE @s table (path varchar(4000));
    
    INSERT @s(path) VALUES
      ('Q:\12345\downloads\randomfilename.png'),
      ('Q:\123_4566\downloads\randomfilename.pdf'),
      ('Q:\CCCMUD\downloads\randomfilename.mp4');
    
    SELECT folder = LEFT(o, CHARINDEX('\', o) - 1) FROM 
    (
      SELECT o = SUBSTRING(path, CHARINDEX('\', path) + 1, 4000)
      FROM @s
    ) AS o;
    

    输出:

    folder
    ----------
    12345
    123_4566
    CCCMUD
    

    但是,对于不包含两个 \ 字符的路径,这会出错。因此,您可能希望向内部查询添加过滤器(或确定在这种情况下您希望如何以不同方式处理输出):

    WHERE path LIKE '%\%\%'
    

    【讨论】:

      【解决方案4】:

      执行此操作的一种简单有效的方法是使用序数拆分器 (like this one)。要确保拆分值仅包含数字,您可以添加 WHERE try_cast(ds.Item as int) is not null。像这样的

      分离器

      CREATE FUNCTION [dbo].[DelimitedSplit8K_LEAD]
      --===== Define I/O parameters
              (@pString VARCHAR(8000), @pDelimiter CHAR(1))
      RETURNS TABLE WITH SCHEMABINDING AS
       RETURN
        WITH E1(N) AS (
                       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                      ),                          --10E+1 or 10 rows
             E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
             E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
       cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front
                           -- for both a performance gain and prevention of accidental "overruns"
                       SELECT 0 UNION ALL
                       SELECT TOP (DATALENGTH(ISNULL(@pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                      ),
      cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                       SELECT t.N+1
                         FROM cteTally t
                        WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0) 
                      )
      --===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
       SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
              Item = SUBSTRING(@pString,s.N1,ISNULL(NULLIF((LEAD(s.N1,1,1) OVER (ORDER BY s.N1) - 1),0)-s.N1,8000))
         FROM cteStart s
      ;
      

      查询

      select ds.*
      from @s s
           cross apply dbo.DelimitedSplit8K_LEAD(s.[path], '\') ds
      where ds.ItemNumber=2
            and try_cast(ds.Item as int) is not null;
      
      ItemNumber  Item
      2           12345
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-13
        • 2020-11-05
        • 2012-11-27
        • 1970-01-01
        • 2016-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多