Comment faire un simple "Rechercher et remplacer" dans MsSQL?

89

La question est assez explicite. Je veux faire une simple recherche et remplacement, comme vous le feriez dans un éditeur de texte sur les données d'une colonne de ma base de données (qui est MsSQL sur MS Windows Server 2003)

Jiaaro
la source

Réponses:

162

La requête suivante remplace chaque acaractère par un bcaractère.

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

Cela ne fonctionnera pas sur SQL Server 2003.

SQLMenace
la source
Si vous obtenez une erreur concernant le type de colonne lorsque vous essayez ceci, consultez la réponse ci-dessous de bmoeskau qui utilise "cast" pour convertir Column1 dans le type requis.
Johnathan Elmore
1
Avons-nous besoin du WHERE?
Anders Lindén
18

ainsi:

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

Exemple: remplace <script ... par <a ... pour éliminer les vulnérabilités javascript

BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;
Jiaaro
la source
Si vous prévoyez réellement de l'utiliser en production, profitez des effets secondaires involontaires des substitutions de chaînes sans contexte.
non, c'était un type de chose «exécuter cette fois pour corriger une attaque par injection SQL» ... maintenant je dois convaincre les pouvoirs en place que nous avons besoin d'une authentification côté serveur. L'authentification Javascript n'est PAS une authentification haha
Jiaaro
Notez qu'il existe beaucoup de méthodes d'injection qui ne nécessitent pas une <script>étiquette, comme l' utilisation <style>ou <object>balises ou malveillants srcattributs ou onerrorattributs.
mbomb007
8

Cela m'a orienté dans la bonne direction, mais j'ai une base de données qui provient de MSSQL 2000 et qui utilise toujours le ntexttype de données pour la colonne que je remplaçais. Lorsque vous essayez d'exécuter REPLACE sur ce type, vous obtenez cette erreur:

Le type de données d'argument ntext n'est pas valide pour l'argument 1 de la fonction de remplacement.

La solution la plus simple, si les données de votre colonne s'inscrivent dans les limites nvarchar, consiste à convertir la colonne lors du remplacement. Emprunter le code de la réponse acceptée :

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

Cela a parfaitement fonctionné pour moi. Merci à ce message de forum que j'ai trouvé pour le correctif. Espérons que cela aide quelqu'un d'autre!

Brian Moeskau
la source
Je savais que je devais lancer ma chronique comme nvarchar, mais je ne connaissais pas nvarchar (max) ... très utile!
Johnathan Elmore
3

Les éléments suivants trouveront et remplaceront une chaîne dans chaque base de données (à l'exclusion des bases de données système) sur chaque table de l'instance à laquelle vous êtes connecté:

Changez simplement 'Search String'pour ce que vous cherchez et 'Replace String'avec ce que vous voulez le remplacer.

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

Remarque: ce n'est pas idéal, ni optimisé

abc123
la source
0

Si vous travaillez avec SQL Server 2005 ou version ultérieure, il existe également une bibliothèque CLR disponible à l' adresse http://www.sqlsharp.com/ qui fournit des implémentations .NET de chaînes et de fonctions RegEx qui, en fonction de votre volume et du type de données, peuvent être plus facile à utiliser et dans certains cas, les fonctions de manipulation de chaînes .NET peuvent être plus efficaces que celles de T-SQL.

Joe Kuemerle
la source