ฉันจะ 'ค้นหาและแทนที่' แบบง่ายๆใน MsSQL ได้อย่างไร?


89

คำถามค่อนข้างอธิบายตัวเองได้ ฉันต้องการค้นหาและแทนที่ง่ายๆเช่นเดียวกับที่คุณทำในโปรแกรมแก้ไขข้อความบนข้อมูลในคอลัมน์ของฐานข้อมูลของฉัน (ซึ่งก็คือ MsSQL บนเซิร์ฟเวอร์ MS Windows 2003)

คำตอบ:


162

แบบสอบถามต่อไปนี้แทนที่aอักขระแต่ละตัวด้วยbอักขระ

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

สิ่งนี้จะไม่ทำงานบนเซิร์ฟเวอร์ SQL 2003


หากคุณได้รับข้อผิดพลาดเกี่ยวกับประเภทคอลัมน์เมื่อคุณลองสิ่งนี้โปรดดูคำตอบด้านล่างจาก bmoeskau ที่ใช้ "cast" เพื่อแปลง Column1 เป็นประเภทที่ต้องการ
Johnathan Elmore

2
เราต้องการWHEREหรือไม่?
Anders Lindén

18

ดังนี้:

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

ตัวอย่าง: แทนที่ <script ... ด้วย <a ... เพื่อกำจัดช่องโหว่ของจาวาสคริปต์

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

หากคุณกำลังวางแผนที่จะใช้สิ่งนั้นในการผลิตจริง ๆ ให้เพลิดเพลินไปกับผลข้างเคียงที่ไม่ได้ตั้งใจของการแทนที่สตริงแบบไม่มีบริบท

ไม่ใช่มันเป็นการ 'เรียกใช้ครั้งเดียวเพื่อแก้ไขการโจมตีด้วยการฉีด sql' ... ตอนนี้ฉันต้องโน้มน้าวอำนาจที่เราต้องการการรับรองความถูกต้องทางฝั่งเซิร์ฟเวอร์ การตรวจสอบความถูกต้องของ Javascript ไม่ใช่การตรวจสอบความถูกต้องฮ่าฮ่า
Jiaaro

ทราบว่ามีความอุดมสมบูรณ์ของวิธีการฉีดที่ไม่จำเป็นต้องมี<script>แท็กเช่นการใช้<style>หรือ<object>แท็กหรือเป็นอันตรายsrcคุณลักษณะหรือonerrorคุณลักษณะ
mbomb007

8

สิ่งนี้ชี้ให้ฉันไปในทิศทางที่ถูกต้อง แต่ฉันมี DB ที่มาจาก MSSQL 2000 และยังคงใช้ntextชนิดข้อมูลสำหรับคอลัมน์ที่ฉันแทนที่ เมื่อคุณพยายามเรียกใช้ REPLACE ในประเภทนั้นคุณจะได้รับข้อผิดพลาดนี้:

ประเภทข้อมูลอาร์กิวเมนต์ ntext ไม่ถูกต้องสำหรับอาร์กิวเมนต์ 1 ของฟังก์ชันแทนที่

วิธีแก้ไขที่ง่ายที่สุดหากข้อมูลคอลัมน์ของคุณพอดีnvarcharคือการส่งคอลัมน์ระหว่างการแทนที่ การยืมรหัสจากคำตอบที่ยอมรับ :

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

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ขอบคุณโพสต์ในฟอรัมนี้ที่ฉันพบสำหรับการแก้ไข หวังว่านี่จะช่วยคนอื่นได้!


ฉันรู้ว่าฉันต้องโยนคอลัมน์ของฉันเป็น nvarchar แต่ไม่รู้เกี่ยวกับ nvarchar (สูงสุด) ... มีประโยชน์มาก!
Johnathan Elmore

3

ต่อไปนี้จะค้นหาและแทนที่สตริงในทุกฐานข้อมูล (ไม่รวมฐานข้อมูลระบบ) ในทุกตารางบนอินสแตนซ์ที่คุณเชื่อมต่อ:

เพียงแค่เปลี่ยน'Search String'เป็นสิ่งที่คุณต้องการและ'Replace String'สิ่งที่คุณต้องการแทนที่ด้วย

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

หมายเหตุ: สิ่งนี้ไม่เหมาะและไม่ได้รับการปรับให้เหมาะสม


0

หากคุณกำลังทำงานกับ SQL Server 2005 หรือใหม่กว่านอกจากนี้ยังมีไลบรารี CLR ที่http://www.sqlsharp.com/ที่ให้การใช้งาน. NET ของฟังก์ชันสตริงและ RegEx ซึ่งขึ้นอยู่กับปริมาณและประเภทข้อมูลของคุณอาจเป็น ใช้งานง่ายกว่าและในบางกรณีฟังก์ชันการจัดการสตริง. NET อาจมีประสิทธิภาพมากกว่าฟังก์ชัน T-SQL

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.