T-SQL elimina todos los caracteres no alfabéticos y no numéricos

¿Existe una forma más inteligente de eliminar todos los caracteres especiales en lugar de tener una serie de aproximadamente 15 declaraciones de reemplazo anidadas?

Lo siguiente funciona, pero solo maneja tres caracteres (ampersand, espacio en blanco y punto).

select CustomerID, CustomerName, 
   Replace(Replace(Replace(CustomerName,'&',''),' ',''),'.','') as CustomerNameStripped
from Customer 

preguntado el 09 de marzo de 12 a las 14:03

5 Respuestas

Una forma flexible;

CREATE FUNCTION [dbo].[fnRemovePatternFromString](@BUFFER VARCHAR(MAX), @PATTERN VARCHAR(128)) RETURNS VARCHAR(MAX) AS
BEGIN
    DECLARE @POS INT = PATINDEX(@PATTERN, @BUFFER)
    WHILE @POS > 0 BEGIN
        SET @BUFFER = STUFF(@BUFFER, @POS, 1, '')
        SET @POS = PATINDEX(@PATTERN, @BUFFER)
    END
    RETURN @BUFFER
END

select dbo.fnRemovePatternFromString('cake & beer $3.99!?c', '%[$&.!?]%')

(No column name)
cake  beer 399c

Respondido 14 Jul 20, 08:07

Veo que todos recomiendan funciones. Me gusta la idea de usar una función definida por el usuario, pero luego tiene que pasar por el control de cambios para llegar al entorno de producción. No hay forma de tener una función en línea en la consulta, ¿verdad? No estoy seguro de qué lenguaje están usando para llamar a la consulta SQL, tal vez VBScript o Powershell, pero ahora creo que será mucho más fácil hacer el stripping en ese lenguaje. - NealWalters

Como una tabla de números o una tabla de calendario, o funciones que dividen o concatenan cadenas, una función que puede hacer este tipo de cosas es un módulo útil para tener a mano. Incluso si no llega de inmediato, debería considerar tener estas cosas en una base de datos de servicios públicos. Tampoco sé si realizar esto en el código siempre es la mejor respuesta, especialmente si varias aplicaciones diferentes necesitan hacer lo mismo ... - Aarón Bertrand

@Alex K., me gusta más esta solución que la mía. Nunca me gustó tener que examinar la cadena un carácter a la vez. ¿Tiene una forma de reemplazar espacios adicionales y caracteres especiales (cr / lf, tab) también? - Dios de datos

En caso de que alguien solo busque INCLUIR alfanumérico, puede usar esto como el patrón con la función anterior: '% [^ a-z0-9]%' - Mackija

Crea una función:

CREATE FUNCTION dbo.StripNonAlphaNumerics
(
  @s VARCHAR(255)
)
RETURNS VARCHAR(255)
AS
BEGIN
  DECLARE @p INT = 1, @n VARCHAR(255) = '';
  WHILE @p <= LEN(@s)
  BEGIN
    IF SUBSTRING(@s, @p, 1) LIKE '[A-Za-z0-9]'
    BEGIN
      SET @n += SUBSTRING(@s, @p, 1);
    END 
    SET @p += 1;
  END
  RETURN(@n);
END
GO

Entonces:

SELECT Result = dbo.StripNonAlphaNumerics
('My Customer''s dog & #1 friend are dope, yo!');

Resultados:

Result
------
MyCustomersdog1friendaredopeyo

Para hacerlo más flexible, puede pasar el patrón que desea permitir:

CREATE FUNCTION dbo.StripNonAlphaNumerics
(
  @s VARCHAR(255),
  @pattern VARCHAR(255)
)
RETURNS VARCHAR(255)
AS
BEGIN
  DECLARE @p INT = 1, @n VARCHAR(255) = '';
  WHILE @p <= LEN(@s)
  BEGIN
    IF SUBSTRING(@s, @p, 1) LIKE @pattern
    BEGIN
      SET @n += SUBSTRING(@s, @p, 1);
    END 
    SET @p += 1;
  END
  RETURN(@n);
END
GO

Entonces:

SELECT r = dbo.StripNonAlphaNumerics
('Bob''s dog & #1 friend are dope, yo!', '[A-Za-z0-9]');

Resultados:

r
------
Bobsdog1friendaredopeyo

Respondido 27 Feb 14, 04:02

@Brian, por favor, no edite el código de otras personas sin darles alguna pista sobre lo que significa "no funcionó". Si tiene un problema con el código, deje un comentario, no lo edite. No tengo idea de por qué su edición funcionó y la original "no funcionó", pero Yo nunca escribiria un codigo como ese. - Aarón Bertrand

Tienes razón, Aaron, mirando hacia atrás sobre esto, fue muy grosero y seguramente estaría muy molesto si yo fuera tú también. Me apresuré a lo grande y me disculpo. Entonces, hasta el punto que estaba tratando de llegar sin usar mis palabras, @c no está definido en su código, por lo que esto no se ejecuta en absoluto. Creo que estaba buscando una estructura de tipo char que tienen algunos otros lenguajes ... Solo necesitaba la primera función, pero la segunda parte probablemente también se vea afectada. Gracias por el código, me ahorró algo de tiempo. :) - Brian Mackay

Veo que lo arreglaste eliminando @c. Gracias. - Brian Mackay

@Brian si, una vez que explicado, Entendí tu edición. Antes de eso, honestamente, no lo hice. Comience con los comentarios antes de editar el código. - Aarón Bertrand

Comprendido. ;) Todos somos muy protectores con nuestro trabajo, aunque en mi caso cualquier cosa escrita ya en 2012 me gustaría poder borrarla por completo porque he aprendido mucho desde entonces ... imagino que siempre será así. Me disculpo de nuevo por ser poco delicado. Gracias. - Brian Mackay

Enfrenté este problema hace varios años, así que escribí una función SQL para hacer el truco. Aquí está el artículo original. (se utilizó para extraer texto de HTML). Desde entonces he actualizado la función, de la siguiente manera:

IF (object_id('dbo.fn_CleanString') IS NOT NULL)
BEGIN
  PRINT 'Dropping: dbo.fn_CleanString'
  DROP function dbo.fn_CleanString
END
GO
PRINT 'Creating: dbo.fn_CleanString'
GO
CREATE FUNCTION dbo.fn_CleanString 
(
  @string varchar(8000)
) 
returns varchar(8000)
AS
BEGIN
---------------------------------------------------------------------------------------------------
-- Title:        CleanString
-- Date Created: March 26, 2011
-- Author:       William McEvoy
--               
-- Description:  This function removes special ascii characters from a string.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


declare @char        char(1),
        @len         int,
        @count       int,
        @newstring   varchar(8000),
        @replacement char(1)

select  @count       = 1,
        @len         = 0,
        @newstring   = '',
        @replacement = ' '



---------------------------------------------------------------------------------------------------
-- M A I N   P R O C E S S I N G
---------------------------------------------------------------------------------------------------


-- Remove Backspace characters
select @string = replace(@string,char(8),@replacement)

-- Remove Tabs
select @string = replace(@string,char(9),@replacement)

-- Remove line feed
select @string = replace(@string,char(10),@replacement)

-- Remove carriage return
select @string = replace(@string,char(13),@replacement)


-- Condense multiple spaces into a single space
-- This works by changing all double spaces to be OX where O = a space, and X = a special character
-- then all occurrences of XO are changed to O,
-- then all occurrences of X  are changed to nothing, leaving just the O which is actually a single space
select @string = replace(replace(replace(ltrim(rtrim(@string)),'  ', ' ' + char(7)),char(7)+' ',''),char(7),'')


--  Parse each character, remove non alpha-numeric

select @len = len(@string)

WHILE (@count <= @len)
BEGIN

  -- Examine the character
  select @char = substring(@string,@count,1)


  IF (@char like '[a-z]') or (@char like '[A-Z]') or (@char like '[0-9]')
    select @newstring = @newstring + @char
  ELSE
    select @newstring = @newstring + @replacement

  select @count = @count + 1

END


return @newstring
END

GO
IF (object_id('dbo.fn_CleanString') IS NOT NULL)
  PRINT 'Function created.'
ELSE
  PRINT 'Function NOT created.'
GO

respondido 09 mar '12, 14:03

Me gusta la idea de usar una función definida por el usuario, pero luego tiene que pasar por el control de cambios para llegar al entorno de producción. - NealWalters

Sé que este es un hilo antiguo, pero aún así, podría ser útil para otros. Aquí hay un rápido y sucio (que hice a la inversa, eliminando los no numéricos), usando un CTE recursivo. Lo que hace que este sea bueno para mí es que es una función en línea, por lo que evita el desagradable efecto RBAR de las funciones escalares y con valores de tabla habituales. Ajuste su filtro según sea necesario para incluir o excluir cualquier tipo de carácter.

        Create Function fncV1_iStripAlphasFromData (
            @iString Varchar(max)
        )
        Returns 
        Table With Schemabinding
        As

            Return(

                with RawData as
                (
                    Select @iString as iString
                )
                ,
                Anchor as
                (

                    Select Case(IsNumeric (substring(iString, 1, 1))) when 1 then substring(iString, 1, 1) else '' End as oString, 2 as CharPos from RawData
                    UNION ALL
                    Select a.oString + Case(IsNumeric (substring(@iString, a.CharPos, 1))) when 1 then substring(@iString, a.CharPos, 1) else '' End, a.CharPos + 1
                    from RawData r
                    Inner Join Anchor a on a.CharPos <= len(rtrim(ltrim(@iString)))

                )

                Select top 1 oString from Anchor order by CharPos Desc

            )

Go

select * from dbo.fncV1_iStripAlphasFromData ('00000')
select * from dbo.fncV1_iStripAlphasFromData ('00A00')
select * from dbo.fncV1_iStripAlphasFromData ('12345ABC6789!&*0')

Respondido el 08 de Septiembre de 15 a las 15:09

Si puedes usar CLR de SQL puede usar expresiones regulares .NET para esto.

Hay un paquete de terceros (gratuito) que incluye esto y más: SQL Sharp .

respondido 09 mar '12, 14:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.