【问题标题】:SQL Server Substring variable length - numerals of varying length with no consistent patternSQL Server 子字符串可变长度 - 不同长度的数字,没有一致的模式
【发布时间】:2020-05-01 10:16:48
【问题描述】:

我已经检查了这里与可变长度子字符串相关的许多线程 - 没有一个回答我的具体情况 - 请不要将其标记为可能重复,除非我以某种方式错过了它。

Azure SQL Server 2017

我在表 dbo.MyTable 中有一个名为 Namevarchar(50) 字段,其中包含以下类型的值:

1143_RRF-tansTracks
DGGP-45-HAEJTJ_wer
3TTKH_YPreTTR
4534554PostRTE
WERET677ITD
PINT_pilly-er_45321

我正在尝试使用SUBSTRING 来获得这个:

1143
45
3
4534554
677
45321

我无法理解如何定义length 参数。

到目前为止我所拥有的:

SUBSTRING(Name, (PATINDEX('%[0-9]%',[Name])),7) AS Number

7 只是作为占位符存在 - 我如何正确编写 length 参数来实现我的号码提取?

【问题讨论】:

  • 您想获取字符串中的所有数字吗?即 abc123def456 返回 123456?还是应该返回 123?还是完全不同的东西?

标签: sql sql-server tsql substring sql-server-2017


【解决方案1】:

您可以将TRANSLATE()REPLACE() 函数用作

SELECT Str,
       REPLACE(
       TRANSLATE(Str, 'abcdefghiJklmnopqrstuvwxyz_-',
                      '                            '), ' ', '')
FROM
(
  VALUES
  ('1143_RRF-tansTracks'),
  ('DGGP-45-HAEJTJ_wer'),
  ('3TTKH_YPreTTR'),
  ('4534554PostRTE'),
  ('WERET677ITD'),
  ('PINT_pilly-er_45321')
) T(Str);

Online Demo

【讨论】:

    【解决方案2】:

    不太好,但如果你真的需要单线:

    SUBSTRING(SUBSTRING(Name, PATINDEX('%[0-9]%',Name),999),1,PATINDEX('%[^0-9]%',SUBSTRING(Name,PATINDEX('%[0-9]%',Name),999)+'x')-1)
    

    或者:

    SUBSTRING(Name,PATINDEX('%[0-9]%',Name),LEN(NAME)-PATINDEX('%[0-9]%',REVERSE(Name))-PATINDEX('%[0-9]%',Name)+2)
    

    【讨论】:

    • 虽然它可能不是最漂亮或最高效的,但我会选择这个,因为它与 SQL 内置功能一起使用,并且不需要我创建自己的函数。其他答案都非常好,我相信这整个线程对其他人会有所帮助。
    【解决方案3】:

    您可以创建一个这样的函数来从 SQL Server 中的字符串中获取数字,如下所示。

    CREATE FUNCTION dbo.udf_GetNumeric (@strAlphaNumeric VARCHAR(256))
    RETURNS VARCHAR(256)
    AS
    BEGIN
        DECLARE @intAlpha INT
    
        SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
    
        BEGIN
            WHILE @intAlpha > 0
            BEGIN
                SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '')
                SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
            END
        END
    
        RETURN ISNULL(@strAlphaNumeric, 0)
    END
    GO
    
    SELECT dbo.udf_GetNumeric('1143_RRF-tansTracks') AS NumberFromString;
    

    这是给定的demo

    【讨论】:

    • 我会避免为此使用标量函数。使用计数表的内联表值函数会使这更快。
    • 是的,对于表列,做一些修改后可以转换成表值函数。
    【解决方案4】:

    这是使用标量函数的替代方法。这将大大超越标量函数。

    create function [dbo].[GetNumbersOnly](@pString varchar(8000))
    returns table as return
        WITH
            E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
            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 (SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4)
        , ValueList as 
        (
            SELECT N, SUBSTRING(@pString, N, 1) as NewVal
            FROM cteTally
            WHERE N <= LEN(@pString)
                AND SUBSTRING(@pString, N, 1) LIKE ('[0-9]')  
        )
    
        SELECT top 1 NewVal = replace(STUFF((
                       SELECT '+' + NewVal
                         FROM ValueList
                          FOR XML PATH(''), TYPE).value('.','varchar(max)'),1,1,''), '+', '')
        FROM ValueList
    

    然后您可以将其用于当前输出。

    declare @Something table
    (
        Name varchar(100)
    )
    
    insert @Something values
    ('1143_RRF-tansTracks')
    , ('DGGP-45-HAEJTJ_wer')
    , ('3TTKH_YPreTTR')
    , ('4534554PostRTE')
    , ('WERET677ITD')
    , ('PINT_pilly-er_45321')
    
    select *
    from @Something s
    cross apply dbo.GetOnlyNumbers(s.Name) n
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-17
      • 2019-12-17
      • 2021-10-14
      • 1970-01-01
      相关资源
      最近更新 更多