Site icon PlusMagi's Blog By Pitt Phunsanit

MSSQL: Batch Alter Table Drop Columns

ตัวอย่าง batch script alter drop column หลาย ๆ column ออกจาก table ในครั้งเดียว และ
batch_alter_table_drop_columns.sql

-- USE DB_DEV;
-- USE DB_QA;
-- USE DB_SIT;
-- USE DB_PRO;

-- 1. Configuration
DECLARE @SchemaName AS NVARCHAR(128) = N'PItt';
DECLARE @TableName AS NVARCHAR(128) = N'Phunsanit';

-- 2. stop scrip if column not null and empty
DECLARE @StopScript BIT = 0; -- flag to stop the script

-- 3. Variables for the script
DECLARE @FullTableName NVARCHAR(257);
DECLARE @TableObjectID INT;
DECLARE @CurrentColumnName NVARCHAR(128);
DECLARE @SqlStatement NVARCHAR(MAX);
DECLARE @HasData BIT = 0;
DECLARE @CheckSql NVARCHAR(MAX);
DECLARE @CheckParams NVARCHAR(100) = N'@HasData BIT OUTPUT';
DECLARE @DataTypeName NVARCHAR(128); -- <-- NEW: To store the column's data type

-- 4. Define the list of columns you want to drop
DECLARE @ColumnsToDrop TABLE (
    ColumnName NVARCHAR(128) PRIMARY KEY
);

INSERT INTO @ColumnsToDrop (ColumnName)
VALUES
    (N'created_at'),
    (N'created_by'),
    (N'deleted_at'),
    (N'deleted_by'),
    (N'updated_at'),
    (N'updated_by'),

-- 5. Store the actual commands to run (if checks pass)
DECLARE @CommandsToRun TABLE (
    SqlStatement NVARCHAR(MAX),
    ColumnName NVARCHAR(128)
);

-- 6. Safety Check: Stop if the table itself doesn't exist
SET @FullTableName = QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName);
SET @TableObjectID = OBJECT_ID(@FullTableName);

IF @TableObjectID IS NULL
BEGIN
    PRINT 'Error: The table ' + @FullTableName + ' does not exist. Halting script.';
    RETURN; -- Stops the script
END

PRINT '--- PRE-CHECK ---';
PRINT 'Checking columns on table: ' + @FullTableName;

-- 7. Create a cursor to loop through and check each column
DECLARE col_cursor CURSOR FOR
SELECT ColumnName FROM @ColumnsToDrop;

OPEN col_cursor;

FETCH NEXT FROM col_cursor INTO @CurrentColumnName;

-- 8. First Loop (Pre-Check)
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @HasData = 0; -- Reset flag for each column

    -- Check if the column exists on this specific table
    IF EXISTS (SELECT 1
               FROM sys.columns c
               WHERE c.object_id = @TableObjectID
                 AND c.name = @CurrentColumnName)
    BEGIN

        -- *** MODIFIED BLOCK ***
        -- First, get the column's data type
        SELECT @DataTypeName = ty.name
        FROM sys.columns c
        JOIN sys.types ty ON c.user_type_id = ty.user_type_id
        WHERE c.object_id = @TableObjectID
          AND c.name = @CurrentColumnName;

        -- Now build the data check SQL based on the type
        IF @DataTypeName IN (N'varchar', N'nvarchar', N'char', N'nchar', N'text', N'ntext')
        BEGIN
            -- For string types, check for NOT NULL AND not empty string (your request)
            -- This means NULLs or '' (empty strings) are OK to drop
            SET @CheckSql = N'SELECT TOP 1 @HasData = 1 FROM ' + @FullTableName +
                            N' WHERE ' + QUOTENAME(@CurrentColumnName) + N' IS NOT NULL' +
                            N' AND ' + QUOTENAME(@CurrentColumnName) + N' != '''''; -- '''' is an escaped '
            PRINT '  [INFO] Column ' + QUOTENAME(@CurrentColumnName) + ' is a string. Checking for data (not NULL and not '''').';
        END
        ELSE
        BEGIN
            -- For non-string types (int, datetime, etc.), just check for NOT NULL
            SET @CheckSql = N'SELECT TOP 1 @HasData = 1 FROM ' + @FullTableName +
                            N' WHERE ' + QUOTENAME(@CurrentColumnName) + N' IS NOT NULL';
            PRINT '  [INFO] Column ' + QUOTENAME(@CurrentColumnName) + ' is not a string. Checking for data (not NULL).';
        END

        -- Run the dynamic check
        EXEC sp_executesql @CheckSql, @CheckParams, @HasData = @HasData OUTPUT;
        -- *** END OF MODIFIED BLOCK ***

        IF @HasData = 1
        BEGIN
            -- Data found! Mark the script to stop.
            PRINT '  [ERROR] Column ' + QUOTENAME(@CurrentColumnName) + ' contains data. Script will be stopped.';
            SET @StopScript = 1;
        END
        ELSE
        BEGIN
            -- Column is empty (all NULL or ''). It is safe to drop.
            PRINT '  [OK] Column ' + QUOTENAME(@CurrentColumnName) + ' is empty. Queued for drop.';

            -- Add the drop command to our queue
            SET @SqlStatement = N'ALTER TABLE ' + @FullTableName +
                                N' DROP COLUMN ' + QUOTENAME(@CurrentColumnName);
            INSERT INTO @CommandsToRun (SqlStatement, ColumnName)
            VALUES (@SqlStatement, @CurrentColumnName);
        END
    END
    ELSE
    BEGIN
        -- Column does not exist, so skip it
        PRINT '  [INFO] Column ' + QUOTENAME(@CurrentColumnName) + ' (does not exist). Skipping.';
    END

    -- Get the next column from the list
    FETCH NEXT FROM col_cursor INTO @CurrentColumnName;
END;

-- 9. Clean up the check cursor
CLOSE col_cursor;
DEALLOCATE col_cursor;

-- 10. THE "STOP" CHECK
PRINT '---';
IF @StopScript = 1
BEGIN
    PRINT 'Execution HALTED. One or more columns contained data (see [ERROR] messages above).';
    PRINT 'No columns were dropped.';
    RETURN; -- This is the STOP you requested
END

-- 11. Execution (only runs if @StopScript is still 0)
PRINT 'All checks passed. Proceeding with drop operations...';

DECLARE exec_cursor CURSOR FOR
SELECT SqlStatement, ColumnName FROM @CommandsToRun;

OPEN exec_cursor;

FETCH NEXT FROM exec_cursor INTO @SqlStatement, @CurrentColumnName;

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        EXEC sp_executesql @SqlStatement;
        PRINT '  Successfully dropped column: ' + QUOTENAME(@CurrentColumnName);
    END TRY
    BEGIN CATCH
        PRINT '  ERROR: Could not drop column ' + QUOTENAME(@CurrentColumnName) + '. Please check dependencies (indexes, constraints).';
        PRINT '  Error Message: ' + ERROR_MESSAGE();
    END CATCH

    FETCH NEXT FROM exec_cursor INTO @SqlStatement, @CurrentColumnName;
END;

-- 12. Clean up the execution cursor
CLOSE exec_cursor;
DEALLOCATE exec_cursor;

PRINT 'Column drop process complete.';

Exit mobile version