Add column to table and then update it inside transaction

后端 未结 6 1803
北荒
北荒 2020-12-08 12:33

I am creating a script that will be run in a MS SQL server. This script will run multiple statements and needs to be transactional, if one of the statement fails the overall

6条回答
  •  我在风中等你
    2020-12-08 13:11

    GO is not a T-SQL command. Is a batch delimiter. The client tool (SSM, sqlcmd, osql etc) uses it to effectively cut the file at each GO and send to the server the individual batches. So obviously you cannot use GO inside IF, nor can you expect variables to span scope across batches.

    Also, you cannot catch exceptions without checking for the XACT_STATE() to ensure the transaction is not doomed.

    Using GUIDs for IDs is always at least suspicious.

    Using NOT NULL constraints and providing a default 'guid' like '{00000000-0000-0000-0000-000000000000}' also cannot be correct.

    Updated:

    • Separate the ALTER and UPDATE into two batches.
    • Use sqlcmd extensions to break the script on error. This is supported by SSMS when sqlcmd mode is on, sqlcmd, and is trivial to support it in client libraries too: dbutilsqlcmd.
    • use XACT_ABORT to force error to interrupt the batch. This is frequently used in maintenance scripts (schema changes). Stored procedures and application logic scripts in general use TRY-CATCH blocks instead, but with proper care: Exception handling and nested transactions.

    example script:

    :on error exit
    
    set xact_abort on;
    go
    
    begin transaction;
    go
    
    if columnproperty(object_id('Code'), 'ColorId', 'AllowsNull') is null
    begin
        alter table Code add ColorId uniqueidentifier null;
    end
    go
    
    update Code 
      set ColorId = '...'
      where ...
    go
    
    commit;
    go
    

    Only a successful script will reach the COMMIT. Any error will abort the script and rollback.

    I used COLUMNPROPERTY to check for column existance, you could use any method you like instead (eg. lookup sys.columns).

提交回复
热议问题