繁体   English   中英

SQL Server 相当于 ORACLE INSTR

[英]SQL Server Equivalent to ORACLE INSTR

我想知道在 SQL Server 中是否有等效于 Oracle INSTR函数?
我知道有CHARINDEXPATINDEX ,但是使用 Oracle 版本我还可以指定我正在寻找的字符的第 N 个外观。

甲骨文INSTR

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

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

您发现 SQL Server 中不存在nth_appearance

无耻地复制为您的问题创建的函数( 相当于 SQL Server 中具有 4 个参数的 Oracle 的 INSTR )(请注意,@Occurs 的使用方式与 Oracle 中的不同 - 您不能指定“第三次出现”,但“出现 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

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

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

您可以使用以下 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

这是 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

试试这个!!

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM