J'essaie d'analyser une valeur d'une chaîne qui implique d'obtenir le lastindex d'un string . Actuellement, je fais un piratage horrible qui consiste à inverser une chaîne:
SELECT REVERSE(SUBSTRING(REVERSE(DB_NAME()), 1,
CHARINDEX('_', REVERSE(DB_NAME()), 1) - 1))
Pour moi, ce code est presque illisible. Je viens de mettre à niveau vers SQL Server 2016 et j'espère qu'il existe un meilleur moyen . Y a-t-il?
Si vous voulez tout après le dernier _
, utilisez:
select right(db_name(), charindex('_', reverse(db_name()) + '_') - 1)
Si vous voulez tout avant, utilisez left()
:
select left(db_name(), len(db_name()) - charindex('_', reverse(db_name()) + '_'))
A écrit 2 fonctions, 1 pour renvoyer LastIndexOf pour le caractère sélectionné.
CREATE FUNCTION dbo.LastIndexOf(@source nvarchar(80), @pattern char)
RETURNS int
BEGIN
RETURN (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
END;
GO
et 1 pour renvoyer une chaîne avant ce LastIndexOf. Peut-être que ce sera utile à quelqu'un.
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
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
Une fois que vous avez l’une des scinder les chaînes d’ici , vous pouvez le faire comme ci-dessous.
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
Non, le serveur SQL n'a pas LastIndexOf.
Voici la chaîne disponible fonctions
Mais vous pouvez toujours créer votre propre fonction
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
Je suis tombé sur ce fil en cherchant une solution à mon problème similaire, qui répondait exactement aux mêmes exigences, mais concernait un type de base de données différent pour lequel il manquait la fonction REVERSE
.
Dans mon cas, il s’agissait d’une base de données OpenEdge (Progress), dont la syntaxe est légèrement différente. Ceci a rendu la fonction INSTR
disponible que la plupart des bases de données typées Oracle offrent .
Alors je suis venu avec le code suivant:
SELECT
INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/', ''))) AS IndexOfLastSlash
FROM foo
Cependant, pour ma situation spécifique (étant la base de données OpenEdge (Progress)), cela ne s'est pas traduit par le comportement souhaité, car remplacer le caractère par un caractère vide donnait la même longueur que la chaîne d'origine. Cela n'a pas beaucoup de sens pour moi mais j'ai pu contourner le problème avec le code ci-dessous:
SELECT
INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/', 'XX')) - LENGTH(foo.filepath)) AS IndexOfLastSlash
FROM foo
Je comprends maintenant que ce code ne résoudra pas le problème de T-SQL car il n’existe pas d’alternative à la fonction INSTR
qui offre la propriété Occurence
.
Par souci de précision, je vais ajouter le code nécessaire à la création de cette fonction scalaire pour pouvoir l’utiliser de la même manière que dans les exemples ci-dessus. Et fera exactement ce que l'OP voulait, sert de méthode LastIndexOf pour 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
Pour éviter ce qui est évident, lorsque la fonction REVERSE
est disponible, vous n'avez pas besoin de créer cette fonction scalaire et vous pouvez simplement obtenir le résultat souhaité comme ceci:
SELECT
LEN(foo.filepath) - CHARINDEX('\', REVERSE(foo.filepath))+1 AS LastIndexOfSlash
FROM foo