How to update primary key

前端 未结 6 1838
萌比男神i
萌比男神i 2020-11-29 07:03

Here is my problem - I have 2 tables:

  1. WORKER, with columns |ID|OTHER_STAF| , where ID is primary key
  2. FIRM, with columns |FPK|ID|SOME
6条回答
  •  清酒与你
    2020-11-29 08:03

    You could use this recursive function for generate necessary T-SQL script.

    CREATE FUNCTION dbo.Update_Delete_PrimaryKey
    (
        @TableName      NVARCHAR(255),
        @ColumnName     NVARCHAR(255),
        @OldValue       NVARCHAR(MAX),
        @NewValue       NVARCHAR(MAX),
        @Del            BIT
    )
    RETURNS NVARCHAR 
    (
        MAX
    )
    AS
    BEGIN
        DECLARE @fks TABLE 
                (
                    constraint_name NVARCHAR(255),
                    table_name NVARCHAR(255),
                    col NVARCHAR(255)
                );
        DECLARE @Sql                  NVARCHAR(MAX),
                @EnableConstraints     NVARCHAR(MAX);
    
        SET @Sql = '';
        SET @EnableConstraints = '';
    
        INSERT INTO @fks
          (
            constraint_name,
            table_name,
            col
          )
        SELECT oConstraint.name     constraint_name,
               oParent.name         table_name,
               oParentCol.name      col
        FROM   sys.foreign_key_columns sfkc
               --INNER JOIN sys.foreign_keys sfk
               --     ON  sfk.[object_id] = sfkc.constraint_object_id
    
               INNER JOIN sys.sysobjects oConstraint
                    ON  sfkc.constraint_object_id = oConstraint.id
               INNER JOIN sys.sysobjects oParent
                    ON  sfkc.parent_object_id = oParent.id
               INNER JOIN sys.all_columns oParentCol
                    ON  sfkc.parent_object_id = oParentCol.object_id
                    AND sfkc.parent_column_id = oParentCol.column_id
               INNER JOIN sys.sysobjects oReference
                    ON  sfkc.referenced_object_id = oReference.id
               INNER JOIN sys.all_columns oReferenceCol
                    ON  sfkc.referenced_object_id = oReferenceCol.object_id
                    AND sfkc.referenced_column_id = oReferenceCol.column_id
        WHERE  oReference.name = @TableName
               AND oReferenceCol.name = @ColumnName
        --AND (@Del <> 1 OR sfk.delete_referential_action = 0)
        --AND (@Del = 1 OR sfk.update_referential_action = 0)
    
        IF EXISTS(
               SELECT 1
               FROM   @fks
           )
        BEGIN
            DECLARE @Constraint     NVARCHAR(255),
                    @Table          NVARCHAR(255),
                    @Col            NVARCHAR(255)  
    
            DECLARE Table_Cursor CURSOR LOCAL 
            FOR
                SELECT f.constraint_name,
                       f.table_name,
                       f.col
                FROM   @fks AS f
    
            OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @Constraint, @Table,@Col  
            WHILE (@@FETCH_STATUS = 0)
            BEGIN
                IF @Del <> 1
                BEGIN
                    SET @Sql = @Sql + 'ALTER TABLE ' + @Table + ' NOCHECK CONSTRAINT ' + @Constraint + CHAR(13) + CHAR(10);
                    SET @EnableConstraints = @EnableConstraints + 'ALTER TABLE ' + @Table + ' CHECK CONSTRAINT ' + @Constraint 
                        + CHAR(13) + CHAR(10);
                END
    
                SET @Sql = @Sql + dbo.Update_Delete_PrimaryKey(@Table, @Col, @OldValue, @NewValue, @Del);
                FETCH NEXT FROM Table_Cursor INTO @Constraint, @Table,@Col
            END
    
            CLOSE Table_Cursor DEALLOCATE Table_Cursor
        END
    
        DECLARE @DataType NVARCHAR(30);
        SELECT @DataType = t.name +
               CASE 
                    WHEN t.name IN ('char', 'varchar', 'nchar', 'nvarchar') THEN '(' +
                         CASE 
                              WHEN c.max_length = -1 THEN 'MAX'
                              ELSE CONVERT(
                                       VARCHAR(4),
                                       CASE 
                                            WHEN t.name IN ('nchar', 'nvarchar') THEN c.max_length / 2
                                            ELSE c.max_length
                                       END
                                   )
                         END + ')'
                    WHEN t.name IN ('decimal', 'numeric') THEN '(' + CONVERT(VARCHAR(4), c.precision) + ',' 
                         + CONVERT(VARCHAR(4), c.Scale) + ')'
                    ELSE ''
               END
        FROM   sys.columns c
               INNER JOIN sys.types t
                    ON  c.user_type_id = t.user_type_id
        WHERE  c.object_id = OBJECT_ID(@TableName)
               AND c.name = @ColumnName
    
        IF @Del <> 1
        BEGIN
            SET @Sql = @Sql + 'UPDATE [' + @TableName + '] SET [' + @ColumnName + '] = CONVERT(' + @DataType + ', ' + ISNULL('N''' + @NewValue + '''', 'NULL') 
                + ') WHERE [' + @ColumnName + '] = CONVERT(' + @DataType + ', ' + ISNULL('N''' + @OldValue + '''', 'NULL') +
                ');' + CHAR(13) + CHAR(10);
            SET @Sql = @Sql + @EnableConstraints;
        END
        ELSE
            SET @Sql = @Sql + 'DELETE [' + @TableName + '] WHERE [' + @ColumnName + '] = CONVERT(' + @DataType + ', N''' + @OldValue 
                + ''');' + CHAR(13) + CHAR(10);
        RETURN @Sql;
    END
    GO
    
    DECLARE @Result NVARCHAR(MAX);
    SET @Result = dbo.Update_Delete_PrimaryKey('@TableName', '@ColumnName', '@OldValue', '@NewValue', 0);/*Update*/
    EXEC (@Result)
    SET @Result = dbo.Update_Delete_PrimaryKey('@TableName', '@ColumnName', '@OldValue', NULL, 1);/*Delete*/
    EXEC (@Result)
    GO
    
    DROP FUNCTION Update_Delete_PrimaryKey;
    

提交回复
热议问题