Como faço um simples 'Localizar e substituir "no MsSQL?

88

A pergunta é bastante autoexplicativa. Quero fazer uma localização e substituição simples, como você faria em um editor de texto nos dados de uma coluna do meu banco de dados (que é MsSQL no MS Windows Server 2003)

Jiaaro
fonte

Respostas:

160

A consulta a seguir substitui cada acaractere por um bcaractere.

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

Isso não funcionará no SQL Server 2003.

SQLMenace
fonte
Se você receber um erro sobre o tipo de coluna ao tentar fazer isso, consulte a resposta abaixo de bmoeskau que usa "elenco" para converter a Coluna1 no tipo necessário.
Johnathan Elmore,
1
Nós precisamos do WHERE?
Anders Lindén
18

igual a:

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

Exemplo: substitui <script ... por <a ... para eliminar vulnerabilidades de javascript

BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;
Jiaaro
fonte
Se você está realmente planejando usar isso na produção, aproveite os efeitos colaterais indesejados de varrer substituições de strings sem contexto.
não, era um tipo de coisa 'execute desta vez para corrigir um ataque de injeção de sql' ... agora eu tenho que convencer as autoridades de que precisamos de autenticação do lado do servidor. Autenticação Javascript NÃO é autenticação haha
Jiaaro
Note-se que há uma abundância de métodos de injeção que não exigem uma <script>tag, como o uso <style>ou <object>etiquetas, ou maliciosas srcatributos ou onerroratributos.
mbomb007
8

Isso me apontou na direção certa, mas eu tenho um banco de dados originado em MSSQL 2000 e ainda está usando o ntexttipo de dados para a coluna que estava substituindo. Ao tentar executar REPLACE nesse tipo, você obtém este erro:

O tipo de dados do argumento ntext é inválido para o argumento 1 da função de substituição.

A correção mais simples, se os dados da coluna se ajustarem nvarchar, é lançar a coluna durante a substituição. Pegando emprestado o código da resposta aceita :

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

Isso funcionou perfeitamente para mim. Graças a esta postagem do fórum que encontrei para a correção. Espero que isso ajude mais alguém!

Brian Moeskau
fonte
Eu sabia que precisava converter minha coluna como nvarchar, mas não sabia sobre nvarchar (max) ... muito útil!
Johnathan Elmore,
3

O seguinte irá encontrar e substituir uma string em cada banco de dados (excluindo bancos de dados do sistema) em cada tabela na instância à qual você está conectado:

Simplesmente mude 'Search String'para o que você procura e 'Replace String'com o que deseja substituir.

--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

Observação: isso não é ideal, nem é otimizado

abc123
fonte
0

Se você estiver trabalhando com o SQL Server 2005 ou posterior, também há uma biblioteca CLR disponível em http://www.sqlsharp.com/ que fornece implementações .NET de funções de string e RegEx que, dependendo do seu volume e tipo de dados, podem ser mais fácil de usar e, em alguns casos, as funções de manipulação de strings .NET podem ser mais eficientes do que as T-SQL.

Joe Kuemerle
fonte