Come faccio a eseguire un semplice "Trova e sostituisci" in MsSQL?


89

La domanda è abbastanza autoesplicativa. Voglio fare una semplice ricerca e sostituzione, come faresti in un editor di testo sui dati in una colonna del mio database (che è MsSQL su MS Windows server 2003)

Risposte:


162

La seguente query sostituisce ogni acarattere con un bcarattere.

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

Questo non funzionerà su SQL Server 2003.


Se ricevi un errore sul tipo di colonna quando lo provi, vedi la risposta di seguito da bmoeskau che utilizza "cast" per convertire Column1 nel tipo richiesto.
Johnathan Elmore

1
Abbiamo bisogno del WHERE?
Anders Lindén

18

così:

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

Esempio: sostituisce <script ... con <a ... per eliminare le vulnerabilità di javascript

BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;

Se hai effettivamente intenzione di usarlo in produzione, goditi i tuoi effetti collaterali indesiderati delle sostituzioni di stringhe senza contesto.

no, era una cosa del tipo "esegui questa volta per riparare un attacco sql injection" ... ora devo convincere i poteri che abbiamo bisogno dell'autenticazione lato server. L'autenticazione Javascript NON è un'autenticazione haha
Jiaaro

Tieni presente che esistono molti metodi di iniezione che non richiedono un <script>tag, come l'utilizzo di <style>o <object>tag o srcattributi o onerrorattributi dannosi .
mbomb007

8

Questo mi ha indirizzato nella giusta direzione, ma ho un DB che ha avuto origine in MSSQL 2000 e sta ancora utilizzando il ntexttipo di dati per la colonna su cui stavo sostituendo. Quando si tenta di eseguire REPLACE su quel tipo, viene visualizzato questo errore:

Il tipo di dati dell'argomento ntext non è valido per l'argomento 1 della funzione di sostituzione.

La soluzione più semplice, se i dati della colonna rientrano nvarchar, è eseguire il cast della colonna durante la sostituzione. Prendendo in prestito il codice dalla risposta accettata :

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

Ha funzionato perfettamente per me. Grazie a questo post sul forum che ho trovato per la correzione. Si spera che questo aiuti qualcun altro!


Sapevo di dover lanciare la mia colonna come nvarchar, ma non sapevo di nvarchar (max) ... molto utile!
Johnathan Elmore

3

Quanto segue troverà e sostituirà una stringa in ogni database (esclusi i database di sistema) su ogni tabella dell'istanza a cui sei connesso:

Cambia semplicemente 'Search String'quello che cerchi e 'Replace String'con quello con cui vuoi sostituirlo.

--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: questo non è l'ideale, né è ottimizzato


0

Se si lavora con SQL Server 2005 o versioni successive, è disponibile anche una libreria CLR all'indirizzo http://www.sqlsharp.com/ che fornisce implementazioni .NET di stringhe e funzioni RegEx che, a seconda del volume e del tipo di dati più facile da usare e in alcuni casi le funzioni di manipolazione delle stringhe .NET possono essere più efficienti di quelle T-SQL.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.