Jak wykonać proste „Znajdź i zamień” w MsSQL?

89

Pytanie jest dość oczywiste. Chcę wykonać proste wyszukiwanie i zamianę, tak jak w edytorze tekstu na danych w kolumnie mojej bazy danych (czyli MsSQL na MS Windows Server 2003)

Jiaaro
źródło

Odpowiedzi:

162

Poniższe zapytanie zastępuje każdy aznak bznakiem.

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

To nie zadziała na SQL Server 2003.

SQLMenace
źródło
Jeśli podczas próby pojawi się błąd dotyczący typu kolumny, zobacz odpowiedź poniżej z witryny bmoeskau, która używa funkcji „rzutowanie” do konwersji kolumny 1 na wymagany typ.
Johnathan Elmore
1
Czy potrzebujemy WHERE?
Anders Lindén
18

tak jak:

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

Przykład: zamienia <script ... na <a ..., aby wyeliminować luki w zabezpieczeniach javascript

BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;
Jiaaro
źródło
Jeśli faktycznie planujesz użyć tego w produkcji, ciesz się niezamierzonymi efektami ubocznymi szerokich bezkontekstowych podstawień ciągów.
nie, to była rzecz typu „uruchom ten jeden raz, aby naprawić atak typu sql injection” ... teraz muszę przekonać siły, że potrzebujemy uwierzytelniania po stronie serwera. Uwierzytelnianie JavaScript NIE JEST uwierzytelnianiem haha
Jiaaro
Zwróć uwagę, że istnieje wiele metod wstrzykiwania, które nie wymagają <script>tagu, takich jak używanie <style>lub <object>tagi lub złośliwe srcatrybuty lub onerroratrybuty.
mbomb007
8

To wskazało mi właściwy kierunek, ale mam bazę danych pochodzącą z MSSQL 2000 i nadal używam ntexttypu danych dla kolumny, w której zastępowałem. Podczas próby uruchomienia polecenia REPLACE na tym typie pojawia się ten błąd:

Typ danych argumentu ntext jest nieprawidłowy dla argumentu 1 funkcji zamiany.

Najprostszym rozwiązaniem, jeśli dane kolumny mieszczą się w obrębie nvarchar, jest rzutowanie kolumny podczas zastępowania. Wypożyczenie kodu z zaakceptowanej odpowiedzi :

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

To zadziałało idealnie dla mnie. Dzięki temu postowi na forum znalazłem poprawkę. Mam nadzieję, że pomoże to komuś innemu!

Brian Moeskau
źródło
Wiedziałem, że muszę rzucić moją kolumnę jako nvarchar, ale nie wiedziałem o nvarchar (max) ... bardzo przydatne!
Johnathan Elmore
3

Poniższe instrukcje znajdują i zastępują ciąg w każdej bazie danych (z wyjątkiem systemowych baz danych) w każdej tabeli w instancji, z którą jesteś połączony:

Po prostu zmień 'Search String'na to, czego szukasz i na 'Replace String'to, czym chcesz to zastąpić.

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

Uwaga: to nie jest idealne, ani nie jest zoptymalizowane

abc123
źródło
0

Jeśli pracujesz z SQL Server 2005 lub nowszym, dostępna jest również biblioteka CLR pod adresem http://www.sqlsharp.com/, która zapewnia implementacje .NET funkcji ciągów i wyrażeń RegEx, które w zależności od wolumenu i typu danych mogą być łatwiejsze w użyciu, aw niektórych przypadkach funkcje manipulowania napisami .NET mogą być bardziej wydajne niż funkcje T-SQL.

Joe Kuemerle
źródło