web-dev-qa-db-ja.com

SQL ServerにLastIndexOfはありますか?

文字列lastindex を取得することを含む文字列から値を解析しようとしています。現在、私はひもを逆にすることを含む恐ろしいハックをしています:

SELECT REVERSE(SUBSTRING(REVERSE(DB_NAME()), 1, 
    CHARINDEX('_', REVERSE(DB_NAME()), 1) - 1))

私にとって、このコードはほとんど読めません。 SQL Server 2016にアップグレードしたばかりですが、もっと良い方法があるといいのですが。ある?

38
AngryHacker

最後の_の後のすべてが必要な場合は、次を使用します。

select right(db_name(), charindex('_', reverse(db_name()) + '_') - 1)

以前にすべてが必要な場合は、left()を使用します。

select left(db_name(), len(db_name()) - charindex('_', reverse(db_name()) + '_'))
111
Gordon Linoff

選択した文字に対してLastIndexOfを返す2つの関数、1を書きました。

CREATE FUNCTION dbo.LastIndexOf(@source nvarchar(80), @pattern char)
RETURNS int
BEGIN  
       RETURN (LEN(@source)) -  CHARINDEX(@pattern, REVERSE(@source)) 
END;  
GO

1。このLastIndexOfの前の文字列を返します。たぶんそれは誰かに役立つでしょう。

CREATE FUNCTION dbo.StringBeforeLastIndex(@source nvarchar(80), @pattern char)
RETURNS nvarchar(80)
BEGIN  
       DECLARE @lastIndex int
       SET @lastIndex = (LEN(@source)) -  CHARINDEX(@pattern, REVERSE(@source)) 

     RETURN SUBSTRING(@source, 0, @lastindex + 1) 
     -- +1 because index starts at 0, but length at 1, so to get up to 11th index, we need LENGTH 11+1=12
END;  
GO
12
user2771704
CREATE FUNCTION dbo.LastIndexOf(@text NTEXT, @delimiter NTEXT)  
RETURNS INT
AS       
BEGIN  
  IF (@text IS NULL) RETURN NULL;
  IF (@delimiter IS NULL) RETURN NULL;
  DECLARE @Text2 AS NVARCHAR(MAX) = @text;
  DECLARE @Delimiter2 AS NVARCHAR(MAX) = @delimiter;
  DECLARE @Index AS INT = CHARINDEX(REVERSE(@Delimiter2), REVERSE(@Text2));
  IF (@Index < 1) RETURN 0;
  DECLARE @ContentLength AS INT = (LEN('|' + @Text2 + '|') - 2);
  DECLARE @DelimiterLength AS INT = (LEN('|' + @Delimiter2 + '|') - 2);
  DECLARE @Result AS INT = (@ContentLength - @Index - @DelimiterLength + 2);
  RETURN @Result;
END
  • "、"(コンマスペース)のような複数文字の区切り文字を許可します。
  • 区切り文字が見つからない場合は0を返します。
  • NVARCHAR(MAX)は暗黙的にNTEXTにキャストされますが、その逆ではないため、快適さの理由でNTEXTを使用します。
  • 先頭または末尾のスペースで区切り文字を正しく処理します!
3
Christoph

ここから分割された文字列 のいずれかを取得したら、このようなセットベースの方法でそれを行うことができます。

declare @string varchar(max)
set @string='C:\Program Files\Microsoft SQL Server\MSSQL\DATA\AdventureWorks_Data.mdf'

;with cte
as
(select *,row_number() over (order by (select null)) as rownum
from [dbo].[SplitStrings_Numbers](@string,'\')
)
select top 1 item from cte order by rownum desc

**Output:**  
AdventureWorks_Data.mdf
3
TheGameiswar

いいえ、SQLサーバーにはLastIndexOfがありません。

これは利用可能な文字列です関数

ただし、いつでも独自の関数を作成できます

CREATE FUNCTION dbo.LastIndexOf(@source text, @pattern char)  
RETURNS 
AS       
BEGIN  
    DECLARE @ret text;  
    SELECT into @ret
           REVERSE(SUBSTRING(REVERSE(@source), 1, 
           CHARINDEX(@pattern, REVERSE(@source), 1) - 1))
    RETURN @ret;  
END;  
GO 
2

まったく同じ要件を持っているが、REVERSE関数を持たない異なる種類のデータベースのための、同様の問題の解決策を探しているときに、このスレッドに出会いました。

私の場合、これはOpenEdge(Progress)データベースの場合で、構文が少し異なります。これにより、INSTR関数が利用可能になりました ほとんどのOracle型付きデータベースが提供

そこで、次のコードを思い付きました。

SELECT 
  INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/',  ''))) AS IndexOfLastSlash 
FROM foo

ただし、OpenEdge(Progress)データベースである特定の状況では、文字を空の文字に置き換えると元の文字と同じ長さになるため、これは望ましい動作になりませんでした文字列。これはあまり意味がありませんが、以下のコードで問題を回避できました。

SELECT 
  INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/',  'XX')) - LENGTH(foo.filepath))  AS IndexOfLastSlash 
FROM foo

今、私はこのコードがT-SQLの問題を解決しないことを理解しています。なぜなら、を提供するINSTR関数に代わるものがないからですOccurenceプロパティ。

念のため、このスカラー関数を作成するために必要なコードを追加して、上記の例で使用したのと同じ方法で使用できるようにします。そして、OPが望んだことを正確に行い、SQL ServerのLastIndexOfメソッドとして機能します。

  -- Drop the function if it already exists
  IF OBJECT_ID('INSTR', 'FN') IS NOT NULL
    DROP FUNCTION INSTR
  GO

  -- User-defined function to implement Oracle INSTR in SQL Server
  CREATE FUNCTION 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

明らかなことを避けるために、REVERSE関数が使用可能な場合、このスカラー関数を作成する必要はなく、次のように必要な結果を得ることができます。

SELECT
  LEN(foo.filepath) - CHARINDEX('\', REVERSE(foo.filepath))+1 AS LastIndexOfSlash 
FROM foo
2
Oceans