2012-03-09 24 views
7

¿Existe alguna manera más inteligente de eliminar todos los caracteres especiales en lugar de tener una serie de aproximadamente 15 declaraciones de reemplazo anidado?Tira de T-SQL todos los caracteres no alfa y no numéricos

Lo siguiente funciona, pero solo maneja tres caracteres (ampersand, blank y period).

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

Respuesta

14

Una manera flexible;

ALTER 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 
+0

Veo que cada uno está recomendando funciones. \t Me gusta la idea de utilizar una función definida por el usuario, pero luego tiene que pasar por 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é idioma están utilizando para llamar a la consulta SQL, tal vez VBScript o Powershell, pero ahora estoy pensando que será mucho más fácil hacer la extracción en ese idioma. – NealWalters

+0

Al igual que 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 cerca. Incluso si no llega inmediatamente, debería considerar tener estas cosas en una base de datos de servicios públicos. No sé si realizar esto en el código siempre es la mejor respuesta, especialmente si múltiples aplicaciones diferentes necesitan hacer lo mismo ... –

+0

@Alex K., me gusta más esta solución que la mía. Nunca me gustó tener que examinar la cuerda un personaje a la vez.¿Tiene alguna forma de reemplazar espacios adicionales y caracteres especiales (cr/lf, tabulación) también? – datagod

1

Si puede utilizar SQL CLR puede utilizar expresiones regulares de .NET de este.

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

6

Me enfrenté a este problema hace varios años, así que escribí una función SQL para hacer el truco. Here is the original article (se utilizó para eliminar texto de HTML). ya que 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 
+0

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

+0

Fantástica solución. – William

7

crear 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 

continuación:

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

Resultados:

Result 
------ 
MyCustomersdog1friendaredopeyo 

Para hacerlo más flexible, podrías pasar el patrón y ou quiere 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 

continuación:

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

Resultados:

r 
------ 
Bobsdog1friendaredopeyo 
+1

@Brian, por favor, no edite el código de otras personas sin darles una pista sobre lo que "no funcionó" significa. Si tiene un problema con el código, deje un comentario, no solo edítelo. No tengo idea de por qué tu edición funcionó y el original "no funcionó", pero [nunca escribiría un código como ese] (http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/bad- habits-to-kick-declarar-varchar-without-length.aspx). –

+0

Tienes razón Aaron, mirando hacia atrás sobre esto, fue muy grosero y seguramente estaría muy molesto si fuera tú también. Corrí a lo grande y me disculpo. Así que al punto que intentaba hacer sin usar mis palabras, @c no está definido en su código, por lo que no se ejecuta en absoluto. Creo que estaba buscando una estructura tipo char que tienen otros idiomas ... 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. :) –

+0

Veo que lo arregló eliminando @c. Gracias. –

1

Sé que esto es un hilo viejo, pero aún así, podría ser útil para otros. He aquí un resumen rápido y sucio (que he hecho a la inversa, eliminando los elementos no numéricos) usando un CTE recursivo. Lo que hace que este sea bueno para mí es que se trata de una función en línea, por lo que evita el desagradable efecto RBAR de las funciones escalares y de tabla habituales. Ajuste su filtro según sea necesario para incluir o excluir los tipos de caracteres.

 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') 
Cuestiones relacionadas