hasta - ¿Hay un LastIndexOf en SQL Server?
sql substring hasta un caracter (6)
Encontré este hilo mientras buscaba una solución a mi problema similar que tenía exactamente el mismo requisito, pero era para un tipo diferente de base de datos que carecía de la función REVERSE
.
En mi caso, esto fue para una base de datos OpenEdge (Progreso) , que tiene una sintaxis ligeramente diferente. Esto hizo que la función INSTR
disponible para mí que la mayoría de las bases de datos de tipo Oracle ofrecen .
Así que se me ocurrió el siguiente código:
SELECT
INSTR(foo.filepath, ''/'',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, ''/'', ''''))) AS IndexOfLastSlash
FROM foo
Sin embargo, para mi situación específica (siendo la base de datos OpenEdge (Progress) ) esto no resultó en el comportamiento deseado porque reemplazar el carácter por un carácter vacío dio la misma longitud que la cadena original. Esto no tiene mucho sentido para mí, pero pude evitar el problema con el siguiente código:
SELECT
INSTR(foo.filepath, ''/'',1, LENGTH( REPLACE( foo.filepath, ''/'', ''XX'')) - LENGTH(foo.filepath)) AS IndexOfLastSlash
FROM foo
Ahora entiendo que este código no solucionará el problema para T-SQL porque no hay alternativa a la función INSTR
que ofrece la propiedad INSTR
.
Solo para ser exhaustivo, agregaré el código necesario para crear esta función escalar para que pueda usarse de la misma manera que lo hice en los ejemplos anteriores. Y hará exactamente lo que el OP quería, servirá como un método LastIndexOf para 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
Para evitar lo obvio, cuando la función REVERSE
está disponible, no necesita crear esta función escalar y puede obtener el resultado requerido de esta manera:
SELECT
LEN(foo.filepath) - CHARINDEX(''/', REVERSE(foo.filepath))+1 AS LastIndexOfSlash
FROM foo
Estoy tratando de analizar un valor de una cadena que implica obtener el last index de una string . Actualmente, estoy haciendo un truco horrible que implica revertir una cadena:
SELECT REVERSE(SUBSTRING(REVERSE(DB_NAME()), 1,
CHARINDEX(''_'', REVERSE(DB_NAME()), 1) - 1))
Para mí este código es casi ilegible. Acabo de actualizar a SQL Server 2016 y espero que haya una mejor manera. ¿Esta ahí?
Escribió 2 funciones, 1 para devolver LastIndexOf para el carácter seleccionado.
CREATE FUNCTION dbo.LastIndexOf(@source nvarchar(20), @pattern char)
RETURNS int
BEGIN
RETURN (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
END;
GO
y 1 para devolver una cadena antes de este LastIndexOf. Tal vez sea de utilidad para alguien.
CREATE FUNCTION dbo.StringBeforeLastIndex(@source nvarchar(20), @pattern char)
RETURNS nvarchar(20)
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
No, el servidor SQL no tiene LastIndexOf.
Estas son las functions cadena disponibles functions
Pero siempre puedes crear tu propia función.
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
Si quieres todo después del último _
, usa:
select right(db_name(), charindex(''_'', reverse(db_name()) + ''_'') - 1)
Si quieres todo antes, usa left()
:
select left(db_name(), len(db_name()) - charindex(''_'', reverse(db_name()) + ''_''))
Una vez que tenga una de las cadenas divididas de aquí , puede hacerlo de una manera basada en un conjunto como este ...
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
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
- Permite delimitadores de múltiples caracteres como "," (espacio de coma).
- Devuelve 0 si no se encuentra el delimitador.
- Toma un NTEXT por razones de comodidad, ya que los NVARCHAR (MAX) se convierten implícitamente en NTEXT, pero no al revés.
- Maneja los delimitadores con el espacio inicial o de cola correctamente!