¿Cómo hago un simple "Buscar y reemplazar" en MsSQL?

89

La pregunta se explica por sí misma. Quiero hacer una búsqueda y reemplazo simple, como lo haría en un editor de texto en los datos en una columna de mi base de datos (que es MsSQL en MS Windows Server 2003)

Jiaaro
fuente

Respuestas:

162

La siguiente consulta reemplaza todos y cada uno de los acaracteres por un bcarácter.

UPDATE 
    YourTable
SET 
    Column1 = REPLACE(Column1,'a','b')
WHERE 
    Column1 LIKE '%a%'

Esto no funcionará en SQL Server 2003.

SQLMenace
fuente
Si obtiene un error sobre el tipo de columna cuando intenta esto, vea la respuesta a continuación de bmoeskau que usa "cast" para convertir Column1 en el tipo requerido.
Johnathan Elmore
1
¿Necesitamos el WHERE?
Anders Lindén
18

al igual que:

BEGIN TRANSACTION; 
UPDATE table_name
  SET column_name=REPLACE(column_name,'text_to_find','replace_with_this'); 
COMMIT TRANSACTION;

Ejemplo: Reemplaza <script ... con <a ... para eliminar vulnerabilidades de JavaScript.

BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;
Jiaaro
fuente
Si realmente planea usar eso en la producción, disfrute de los efectos secundarios no deseados de las sustituciones de cuerdas sin contexto.
no, fue un tipo de cosa de 'ejecutar esta vez para arreglar un ataque de inyección SQL' ... ahora tengo que convencer a los poderes fácticos de que necesitamos autenticación del lado del servidor. La autenticación de Javascript NO es autenticación jaja
Jiaaro
Tenga en cuenta que hay un montón de métodos de inyección que no requieren una <script>etiqueta, como el uso <style>o <object>etiquetas, o maliciosos srcatributos o onerroratributos.
mbomb007
8

Esto me indicó la dirección correcta, pero tengo una base de datos que se originó en MSSQL 2000 y todavía ntextestoy usando el tipo de datos para la columna que estaba reemplazando. Cuando intenta ejecutar REPLACE en ese tipo, aparece este error:

El tipo de datos de argumento ntext no es válido para el argumento 1 de la función de reemplazo.

La solución más simple, si los datos de la columna encajan dentro nvarchar, es convertir la columna durante el reemplazo. Tomando prestado el código de la respuesta aceptada :

UPDATE YourTable
SET Column1 = REPLACE(cast(Column1 as nvarchar(max)),'a','b')
WHERE Column1 LIKE '%a%'

Esto funcionó perfectamente para mí. Gracias a esta publicación del foro que encontré por la solución. ¡Ojalá esto ayude a alguien más!

Brian Moeskau
fuente
Sabía que tenía que convertir mi columna como nvarchar, pero no sabía sobre nvarchar (max) ... ¡muy útil!
Johnathan Elmore
3

Lo siguiente buscará y reemplazará una cadena en cada base de datos (excluyendo las bases de datos del sistema) en cada tabla en la instancia a la que está conectado:

Simplemente cambie 'Search String'a lo que busque y 'Replace String'con lo que quiera reemplazarlo.

--Getting all the databases and making a cursor
DECLARE db_cursor CURSOR FOR  
SELECT name 
FROM master.dbo.sysdatabases 
WHERE name NOT IN ('master','model','msdb','tempdb')  -- exclude these databases

DECLARE @databaseName nvarchar(1000)
--opening the cursor to move over the databases in this instance
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @databaseName   

WHILE @@FETCH_STATUS = 0   
BEGIN
    PRINT @databaseName
    --Setting up temp table for the results of our search
    DECLARE @Results TABLE(TableName nvarchar(370), RealColumnName nvarchar(370), ColumnName nvarchar(370), ColumnValue nvarchar(3630))

    SET NOCOUNT ON

    DECLARE @SearchStr nvarchar(100), @ReplaceStr nvarchar(100), @SearchStr2 nvarchar(110)
    SET @SearchStr = 'Search String'
    SET @ReplaceStr = 'Replace String'
    SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')

    DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128)
    SET  @TableName = ''

    --Looping over all the tables in the database
    WHILE @TableName IS NOT NULL
    BEGIN
        DECLARE @SQL nvarchar(2000)
        SET @ColumnName = ''
        DECLARE @result NVARCHAR(256)
        SET @SQL = 'USE ' + @databaseName + '
            SELECT @result = MIN(QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME))
            FROM    [' + @databaseName + '].INFORMATION_SCHEMA.TABLES
            WHERE       TABLE_TYPE = ''BASE TABLE'' AND TABLE_CATALOG = ''' + @databaseName + '''
                AND QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME) > ''' + @TableName + '''
                AND OBJECTPROPERTY(
                        OBJECT_ID(
                            QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME)
                                ), ''IsMSShipped''
                                ) = 0'
        EXEC master..sp_executesql @SQL, N'@result nvarchar(256) out', @result out

        SET @TableName = @result
        PRINT @TableName

        WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
        BEGIN
            DECLARE @ColumnResult NVARCHAR(256)
            SET @SQL = '
                SELECT @ColumnResult = MIN(QUOTENAME(COLUMN_NAME))
                FROM    [' + @databaseName + '].INFORMATION_SCHEMA.COLUMNS
                WHERE       TABLE_SCHEMA    = PARSENAME(''[' + @databaseName + '].' + @TableName + ''', 2)
                    AND TABLE_NAME  = PARSENAME(''[' + @databaseName + '].' + @TableName + ''', 1)
                    AND DATA_TYPE IN (''char'', ''varchar'', ''nchar'', ''nvarchar'')
                    AND TABLE_CATALOG = ''' + @databaseName + '''
                    AND QUOTENAME(COLUMN_NAME) > ''' + @ColumnName + ''''
            PRINT @SQL
            EXEC master..sp_executesql @SQL, N'@ColumnResult nvarchar(256) out', @ColumnResult out
            SET @ColumnName = @ColumnResult 

            PRINT @ColumnName

            IF @ColumnName IS NOT NULL
            BEGIN
                INSERT INTO @Results
                EXEC
                (
                    'USE ' + @databaseName + '
                    SELECT ''' + @TableName + ''',''' + @ColumnName + ''',''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
                    FROM ' + @TableName + ' (NOLOCK) ' +
                    ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
                )
            END
        END
    END

    --Declaring another temporary table
    DECLARE @time_to_update TABLE(TableName nvarchar(370), RealColumnName nvarchar(370))

    INSERT INTO @time_to_update
    SELECT TableName, RealColumnName FROM @Results GROUP BY TableName, RealColumnName

    DECLARE @MyCursor CURSOR;
    BEGIN
        DECLARE @t nvarchar(370)
        DECLARE @c nvarchar(370)
        --Looping over the search results   
        SET @MyCursor = CURSOR FOR
        SELECT TableName, RealColumnName FROM @time_to_update GROUP BY TableName, RealColumnName

        --Getting my variables from the first item
        OPEN @MyCursor 
        FETCH NEXT FROM @MyCursor 
        INTO @t, @c

        WHILE @@FETCH_STATUS = 0
        BEGIN
            -- Updating the old values with the new value
            DECLARE @sqlCommand varchar(1000)
            SET @sqlCommand = '
                USE ' + @databaseName + '
                UPDATE [' + @databaseName + '].' + @t + ' SET ' + @c + ' = REPLACE(' + @c + ', ''' + @SearchStr + ''', ''' + @ReplaceStr + ''') 
                WHERE ' + @c + ' LIKE ''' + @SearchStr2 + ''''
            PRINT @sqlCommand
            BEGIN TRY
                EXEC (@sqlCommand)
            END TRY
            BEGIN CATCH
                PRINT ERROR_MESSAGE()
            END CATCH

            --Getting next row values
            FETCH NEXT FROM @MyCursor 
            INTO @t, @c 
        END;

        CLOSE @MyCursor ;
        DEALLOCATE @MyCursor;
    END;

    DELETE FROM @time_to_update
    DELETE FROM @Results

    FETCH NEXT FROM db_cursor INTO @databaseName
END   

CLOSE db_cursor   
DEALLOCATE db_cursor

Nota: esto no es ideal ni está optimizado

abc123
fuente
0

Si está trabajando con SQL Server 2005 o posterior, también hay una biblioteca CLR disponible en http://www.sqlsharp.com/ que proporciona implementaciones .NET de funciones de cadena y RegEx que, dependiendo de su volumen y tipo de datos, pueden ser más fácil de usar y, en algunos casos, las funciones de manipulación de cadenas de .NET pueden ser más eficientes que las de T-SQL.

Joe Kuemerle
fuente