【问题标题】:SQL Server Equivalent to ORACLE INSTRSQL Server 等效于 ORACLE INSTR
【发布时间】:2011-05-01 09:28:07
【问题描述】:

我想知道在 SQL Server 中是否有与 Oracle INSTR 等效的函数?
我知道有CHARINDEXPATINDEX,但是使用Oracle 版本我还可以指定我要查找的字符的第N 次出现。

甲骨文INSTR

instr( string1, string2 [, start_position [, **nth_appearance** ] ] )

CHARINDEX 几乎可以让我到达那里,但我想让它从字符串中字符的 nth_appearance 开始。

【问题讨论】:

    标签: sql sql-server-2005 tsql sql-server-2008


    【解决方案1】:

    这里是 Oracle 的 INSTR 函数的一个版本,它也适用于反向查找的负位置,根据这里的 Oracle 文档:- https://docs.oracle.com/cd/B28359_01/olap.111/b28126/dml_functions_1103.htm#OLADM564

    CREATE FUNCTION dbo.INSTR(@str NVARCHAR(MAX), @substr NVARCHAR(MAX), @position INT = 1, @occurance INT = 1)
    RETURNS INT
    AS
    BEGIN
        DECLARE @loc INT = @position;
    
        IF @loc < 0
        BEGIN
            SET @str = REVERSE(@str);
            SET @substr = REVERSE(@substr);
            SET @loc = @loc * -1;
        END
    
        IF @loc > 0
        BEGIN
            SET @loc = @loc - 1;
        END
    
        WHILE (@occurance > 0 AND CHARINDEX(@substr, @str, @loc + 1) > 0)
        BEGIN
            SET @loc = CHARINDEX(@substr, @str, @loc + 1);
            SET @occurance = @occurance - 1;
        END
    
        IF @occurance > 0
        BEGIN
            SET @loc = 0;
        END
    
        IF @position < 0
        BEGIN
            SET @loc = LEN(@str) - @loc;
        END
    
        RETURN @loc
    END
    

    【讨论】:

      【解决方案2】:

      试试这个!!

      CREATE FUNCTION dbo.INSTR (@str VARCHAR(8000), @substr VARCHAR(255), @start INT, @occurrence INT)
        RETURNS INT  
        AS
        BEGIN
          DECLARE @found INT = @occurrence,
                  @pos INT = @start;
      
          WHILE 1=1 
          BEGIN
              -- Find the next occurrence
              SET @pos = CHARINDEX(@substr, @str, @pos);
      
              -- Nothing found
              IF @pos IS NULL OR @pos = 0
                  RETURN @pos;
      
              -- The required occurrence found
              IF @found = 1
                  BREAK;
      
              -- Prepare to find another one occurrence
              SET @found = @found - 1;
              SET @pos = @pos + 1;
          END
      
          RETURN @pos;
        END
        GO
      

      用法:

      -- 查找第二次出现的字母 'o'
      SELECT dbo.INSTR('莫斯科', 'o', 1, 2);
      -- 结果:5

      【讨论】:

        【解决方案3】:

        您可以使用以下 UDF(内联函数而不是标量

         CREATE FUNCTION dbo.INSTR 
         (
         @str VARCHAR(8000),
         @Substr VARCHAR(1000),
         @start INT ,
         @Occurance INT
         )
         RETURNS TABLE 
         AS 
         RETURN
        
        WITH Tally (n) AS
        (
            SELECT TOP (LEN(@str)) ROW_NUMBER()  OVER (ORDER BY (SELECT NULL)) 
            FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0)) a(n)
            CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
            CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
            CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n)
        )
        
        , Find_N_STR as
        (
           SELECT 
            CASE WHEN DENSE_RANK() OVER(PARTITION BY @Substr ORDER BY (CHARINDEX(@Substr ,@STR ,N))) = @Occurance 
             THEN MAX(N-@start +1) OVER (PARTITION BY CHARINDEX(@Substr ,@STR ,N) ) 
             ELSE 0 
             END [Loc]
        FROM Tally
        WHERE CHARINDEX(@Substr ,@STR ,N) > 0 
        )
        
        SELECT Loc= MAX(Loc) 
        FROM Find_N_STR
        WHERE Loc > 0 
        

        使用方法:

         declare @T table 
         (
         Name_Level_Class_Section varchar(25)
         )
         insert into @T values
          ('Jacky_1_B2_23'),
          ('Johnhy_1_B2_24'),
          ('Peter_2_A5_3')
        
          select t.Name_Level_Class_Section  , l.Loc
          from @t t
          cross apply  dbo.INSTR (t.Name_Level_Class_Section, '_',1,2) l
        

        【讨论】:

          【解决方案4】:

          @str1 varchar(8000), @str2 varchar(1000) 更改为@str1 varchar(1000), @str2 varchar(8000)

          或 将CHARINDEX(@str1, @str2, @LastPosition + 1) 更改为CHARINDEX(@str2, @str1, @LastPosition + 1)

          【讨论】:

            【解决方案5】:

            您发现nth_appearance 在 SQL Server 中不存在。

            无耻地复制为您的问题创建的函数 (Equivalent of Oracle's INSTR with 4 parameters in SQL Server)(请注意 @Occurs 的使用方式与 Oracle 中的不同 - 您不能指定“第 3 次出现”,但“出现 3 次”):

            CREATE FUNCTION udf_Instr
                (@str1 varchar(8000), @str2 varchar(1000), @start int, @Occurs int)
            RETURNS int
            AS
            BEGIN
                DECLARE @Found int, @LastPosition int
                SET @Found = 0
                SET @LastPosition = @start - 1
            
                WHILE (@Found < @Occurs)
                BEGIN
                    IF (CHARINDEX(@str1, @str2, @LastPosition + 1) = 0)
                        BREAK
                      ELSE
                        BEGIN
                            SET @LastPosition = CHARINDEX(@str1, @str2, @LastPosition + 1)
                            SET @Found = @Found + 1
                        END
                END
            
                RETURN @LastPosition
            END
            GO
            
            SELECT dbo.udf_Instr('x','axbxcxdx',1,4)
            GO
            
            
            DROP FUNCTION udf_Instr
            GO
            

            【讨论】:

            • Thansk moontear .....我创建了一个函数,只是希望我可以使用 sql server 函数。感谢功能示例。
            猜你喜欢
            • 1970-01-01
            • 2014-05-30
            • 1970-01-01
            • 2011-09-04
            • 2021-10-26
            • 2021-11-18
            • 2014-02-20
            • 2020-12-15
            • 2015-07-09
            相关资源
            最近更新 更多