it-swarm.com.de

Gibt es ein LastIndexOf in SQL Server?

Ich versuche, einen Wert aus einer Zeichenfolge zu analysieren, die den letztenIndex einer Zeichenfolge enthält. Derzeit mache ich einen schrecklichen Hack, bei dem eine Saite umgekehrt wird:

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

Für mich ist dieser Code kaum lesbar. Ich habe gerade ein Upgrade auf SQL Server 2016 durchgeführt und hoffe, dass es einen besseren Weg gibt.

31
AngryHacker

Wenn Sie alles nach dem letzten _ wünschen, verwenden Sie:

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

Wenn Sie alles vorher wollen, verwenden Sie left():

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

Schrieb 2 Funktionen, 1, um LastIndexOf für das ausgewählte Zeichen zurückzugeben.

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

und 1, um eine Zeichenfolge vor diesem LastIndexOf zurückzugeben. Vielleicht wird es jemandem nützlich sein.

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
10
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
  • Erlaubt Trennzeichen mit mehreren Zeichen wie "," (Komma-Leerzeichen). 
  • Gibt 0 zurück, wenn das Trennzeichen nicht gefunden wird.
  • Nimmt aus Komfortgründen einen NTEXT an, da NVARCHAR (MAX) implizit in NTEXT umgewandelt werden, jedoch nicht umgekehrt.
  • Behandelt Trennzeichen mit Vor- oder Nachlaufzeichen korrekt!
2
Christoph

Sobald Sie eine der Split-Strings von hier haben, können Sie dies auf eine bestimmte Art und Weise tun. 

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
2
TheGameiswar

Nein, der SQL-Server verfügt nicht über LastIndexOf.

Dies sind die verfügbaren Zeichenketten Funktionen

Sie können jedoch jederzeit Ihre eigene Funktion erstellen

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

Ich bin auf diesen Thread gestoßen, als ich nach einer Lösung für mein ähnliches Problem gesucht habe, die genau die gleiche Anforderung hatte, aber für eine andere Art von Datenbank gedacht war, der die REVERSE-Funktion fehlte.

In meinem Fall war dies eine OpenEdge (Progress) Datenbank, die eine etwas andere Syntax hat. Dadurch wurde die Funktion INSTR für mich verfügbar, die die meisten von Oracle typisierten Datenbanken anbieten.

Also kam mir folgender Code:

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

In meiner speziellen Situation (die Datenbank OpenEdge (Progress)) führte dies jedoch nicht zu dem gewünschten Verhalten, da das Ersetzen des Zeichens durch ein leeres Zeichen dieselbe Länge wie der ursprüngliche String ergab. Das macht für mich nicht viel Sinn, aber ich konnte das Problem mit dem folgenden Code umgehen:

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

Jetzt verstehe ich, dass dieser Code das Problem für T-SQL nicht lösen kann, da es keine Alternative zur INSTR-Funktion gibt, die die Occurence-Eigenschaft anbietet.

Um gründlich zu sein, füge ich den Code hinzu, der zum Erstellen dieser Skalarfunktion benötigt wird, damit er auf dieselbe Weise wie in den obigen Beispielen verwendet werden kann. Und wird genau das tun, was das OP wollte, als LastIndexOf -Methode für SQL Server.

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

Um das Offensichtliche zu vermeiden, müssen Sie, wenn die Funktion REVERSE verfügbar ist, diese Skalarfunktion nicht erstellen. Sie können das erforderliche Ergebnis wie folgt erhalten:

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