Patrón Regex dentro de la función Reemplazar SQL?

SELECT REPLACE('100.00 GB', '%^(^-?\d*\.{0,1}\d+$)%', ''); 

Quiero reemplazar cualquier marcado entre dos partes del número con la expresión regular anterior, pero parece que no funciona. No estoy seguro si es la syntax de expresiones regulares lo que está mal porque intenté con algo más simple como '%[^0-9]%' solo para probar, pero tampoco funcionó. ¿Alguien sabe cómo puedo lograr esto?

Puede usar PATINDEX para encontrar el primer índice de la ocurrencia del patrón (cadena). Luego use STUFF para rellenar otra cadena en el patrón (cadena) emparejado.

Pasa por cada fila. Reemplaza cada carácter ilegal con lo que quieras. En su caso, reemplace no numérico con blanco. El bucle interno es si tiene más de un carácter ilegal en una celda actual que el del bucle.

 DECLARE @counter int SET @counter = 0 WHILE(@counter < (SELECT MAX(ID_COLUMN) FROM Table)) BEGIN WHILE 1 = 1 BEGIN DECLARE @RetVal varchar(50) SET @RetVal = (SELECT Column = STUFF(Column, PATINDEX('%[^0-9.]%', Column),1, '') FROM Table WHERE ID_COLUMN = @counter) IF(@RetVal IS NOT NULL) UPDATE Table SET Column = @RetVal WHERE ID_COLUMN = @counter ELSE break END SET @counter = @counter + 1 END 

Precaución: ¡Esto es lento! Tener una columna varchar puede tener impacto. Entonces, usar LTRIM RTRIM puede ayudar un poco. De todos modos, es lento.

El crédito va a esta respuesta de StackOverFlow.

EDITAR Crédito también va a @srutzky

Editar (por @Tmdean) En lugar de hacer una fila a la vez, esta respuesta se puede adaptar a una solución más basada en conjuntos. Todavía itera la cantidad máxima de caracteres no numéricos en una sola fila, por lo que no es ideal, pero creo que debería ser aceptable en la mayoría de las situaciones.

 WHILE 1 = 1 BEGIN WITH q AS (SELECT ID_Column, PATINDEX('%[^0-9.]%', Column) AS n FROM Table) UPDATE Table SET Column = STUFF(Column, qn, 1, '') FROM q WHERE Table.ID_Column = q.ID_Column AND qn != 0; IF @@ROWCOUNT = 0 BREAK; END; 

También puede mejorar bastante la eficiencia si mantiene una columna de bit en la tabla que indica si el campo ya se ha borrado. (NULL representa "Desconocido" en mi ejemplo y debe ser el predeterminado de la columna).

 DECLARE @done bit = 0; WHILE @done = 0 BEGIN WITH q AS (SELECT ID_Column, PATINDEX('%[^0-9.]%', Column) AS n FROM Table WHERE COALESCE(Scrubbed_Column, 0) = 0) UPDATE Table SET Column = STUFF(Column, qn, 1, ''), Scrubbed_Column = 0 FROM q WHERE Table.ID_Column = q.ID_Column AND qn != 0; IF @@ROWCOUNT = 0 SET @done = 1; -- if Scrubbed_Column is still NULL, then the PATINDEX -- must have given 0 UPDATE table SET Scrubbed_Column = CASE WHEN Scrubbed_Column IS NULL THEN 1 ELSE NULLIF(Scrubbed_Column, 0) END; END; 

Si no desea cambiar su esquema, esto es fácil de adaptar para almacenar los resultados intermedios en una variable con valores de tabla que se aplica a la tabla real al final.

En un sentido general, SQL Server no admite expresiones regulares y no puede usarlas en el código T-SQL nativo.

Podría escribir una función CLR para hacer eso. Mira aquí , por ejemplo.

En lugar de eliminar el carácter encontrado por su única posición, el uso de Replace(Column, BadFoundCharacter, '') podría ser sustancialmente más rápido. Además, en lugar de simplemente reemplazar el carácter malo que se encuentra a continuación en cada columna, esto reemplaza a todos los encontrados.

 WHILE 1 = 1 BEGIN UPDATE dbo.YourTable SET Column = Replace(Column, Substring(Column, PatIndex('%[^0-9.-]%', Column), 1), '') WHERE Column LIKE '%[^0-9.-]%' If @@RowCount = 0 BREAK; END; 

Estoy convencido de que esto funcionará mejor que la respuesta aceptada, aunque solo sea porque hace menos operaciones. Hay otras formas que también podrían ser más rápidas, pero no tengo tiempo para explorarlas en este momento.

Envolver la solución dentro de una función SQL podría ser útil si desea reutilizarla. Incluso lo estoy haciendo a nivel celular, por eso lo estoy planteando como una respuesta diferente:

 CREATE FUNCTION [dbo].[fnReplaceInvalidChars] (@string VARCHAR(300)) RETURNS VARCHAR(300) BEGIN DECLARE @str VARCHAR(300) = @string; DECLARE @Pattern VARCHAR (20) = '%[^a-zA-Z0-9]%'; DECLARE @Len INT; SELECT @Len = LEN(@String); WHILE @Len > 0 BEGIN SET @Len = @Len - 1; IF (PATINDEX(@Pattern,@str) > 0) BEGIN SELECT @str = STUFF(@str, PATINDEX(@Pattern,@str),1,''); END ELSE BEGIN BREAK; END END RETURN @str END 

Si está haciendo esto solo para un parámetro que entra en un Procedimiento almacenado, puede usar lo siguiente:

 while PatIndex('%[^0-9]%', @Param) > 0 select @Param = Replace(@Param, Substring(@Param, PatIndex('%[^0-9]%', @Param), 1), '') 

Aquí hay una función recursiva que escribí para lograr esto basada en las respuestas anteriores.

 CREATE FUNCTION dbo.RecursiveReplace ( @P_String VARCHAR(MAX), @P_Pattern VARCHAR(MAX), @P_ReplaceString VARCHAR(MAX), @P_ReplaceLength INT = 1 ) RETURNS VARCHAR(MAX) BEGIN DECLARE @Index INT; -- Get starting point of pattern SET @Index = PATINDEX(@P_Pattern, @P_String); IF @Index > 0 BEGIN -- Perform the replace SET @P_String = STUFF(@P_String, PATINDEX(@P_Pattern, @P_String), @P_ReplaceLength, @P_ReplaceString); -- Recurse SET @P_String = dbo.RecursiveReplace(@P_String, @P_Pattern, @P_ReplaceString, @P_ReplaceLength); END; RETURN @P_String; END; 

Esencia

Me encontré con esta publicación buscando algo más, pero pensé que mencionaría una solución que uso que es mucho más eficiente, y realmente debería ser la implementación predeterminada de cualquier función cuando se utiliza con una consulta basada en conjuntos, que es usar una cruz aplicada función de tabla. Parece que el tema todavía está activo, así que espero que esto sea útil para alguien.

Ejemplo de tiempo de ejecución en algunas de las respuestas hasta ahora basadas en ejecutar consultas basadas en conjuntos recursivos o función escalar, basado en el conjunto de prueba de 1m rows eliminando los caracteres de un newid aleatorio, oscila entre 34s y 2m05s para los ejemplos de ciclo WHILE y desde 1m3s hasta { forever} para los ejemplos de funciones.

El uso de una función de tabla con aplicación cruzada logra el mismo objective en 10s . Es posible que deba ajustarlo para satisfacer sus necesidades, como la longitud máxima que maneja.

Función:

 CREATE FUNCTION [dbo].[RemoveChars](@InputUnit VARCHAR(40)) RETURNS TABLE AS RETURN ( WITH Numbers_prep(Number) AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 ) ,Numbers(Number) AS ( SELECT TOP (ISNULL(LEN(@InputUnit),0)) row_number() OVER (ORDER BY (SELECT NULL)) FROM Numbers_prep a CROSS JOIN Numbers_prep b ) SELECT OutputUnit FROM ( SELECT substring(@InputUnit,Number,1) FROM Numbers WHERE substring(@InputUnit,Number,1) like '%[0-9]%' ORDER BY Number FOR XML PATH('') ) Sub(OutputUnit) ) 

Uso:

 UPDATE t SET column = o.OutputUnit FROM ##tt CROSS APPLY [dbo].[RemoveChars](t.column) o 

Creo que un enfoque más simple y rápido es iterado por cada carácter del alfabeto:

 DECLARE @i int SET @i = 0 WHILE(@i < 256) BEGIN IF char(@i) NOT IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.') UPDATE Table SET Column = replace(Column, char(@i), '') SET @i = @i + 1 END