Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何更新主键_Sql Server_Sql Server 2008_Foreign Keys_Composite Primary Key - Fatal编程技术网

Sql server 如何更新主键

Sql server 如何更新主键,sql-server,sql-server-2008,foreign-keys,composite-primary-key,Sql Server,Sql Server 2008,Foreign Keys,Composite Primary Key,这是我的问题-我有两张表: WORKER,具有列| ID | OTHER_STAF |,其中ID是主键 FIRM,带有列| FPK | ID | SOMETHING | |,其中FPK和ID组合构成主键,并且ID是引用WORKER.ID的外键(不为null,并且必须与WORKER中的值相同) 我想让存储过程更新\u ID\u WORKER,在这里我想更改WORKER中特定ID的值,并且在所有实例中更改FIRM中特定ID的值。不要更新主键。如果有任何其他表引用数据,那么它可能会给保持数据完整性带来

这是我的问题-我有两张表:

  • WORKER,具有列
    | ID | OTHER_STAF |
    ,其中ID是主键
  • FIRM,带有列
    | FPK | ID | SOMETHING | |
    ,其中FPK和ID组合构成主键,并且ID是引用WORKER.ID的外键(不为null,并且必须与WORKER中的值相同)

  • 我想让存储过程
    更新\u ID\u WORKER
    ,在这里我想更改WORKER中特定ID的值,并且在所有实例中更改FIRM中特定ID的值。

    不要更新主键。如果有任何其他表引用数据,那么它可能会给保持数据完整性带来很多问题


    理想情况下,如果您想要一个可更新的唯一字段,请创建一个新字段。

    您不应该这样做,而应该插入一个新记录,并以这种方式进行更新。
    但是,如果确实需要,您可以执行以下操作:

    • 暂时禁用强制执行FK约束(例如,
      ALTER TABLE foo WITH NOCHECK CONSTRAINT ALL
    • 然后更新你的PK
    • 然后更新FKs以匹配PK更改
    • 最后启用反向强制FK约束

    当您发现有必要更新主键值以及所有匹配的外键时,则需要修复整个设计

    级联所有必要的外键更改是很棘手的。最好不要更新主键,如果有必要,应该使用
    代理主键
    ,该主键不是从应用程序数据派生的。因此,它的价值与业务逻辑无关,永远不需要更改(最终用户应该看不见)。然后可以更新和显示其他列

    例如:

    BadUserTable
    UserID     varchar(20) primary key --user last name
    other columns...
    
    如果您创建了许多表,这些表都有一个FK-to-UserID,用来跟踪用户所做的一切,但是该用户结婚后想要一个与他们的新姓氏匹配的ID,那么您就不走运了

    GoodUserTable
    UserID    int identity(1,1) primary key
    UserLogin varchar(20) 
    other columns....
    
    现在,您将代理主键FK到所有其他表,并在必要时显示UserLogin,允许他们使用该值登录,当他们需要更改时,您只在一行的一列中更改它。

    首先,我们选择稳定(非静态)数据列来形成主键,正是因为更新关系数据库中的键(其中引用是按键进行的)是我们希望避免的事情

  • 对于这个问题,键是否是关系键(“由数据组成”)并因此具有关系完整性、能力和速度,或者“键”是否是记录ID而没有关系完整性、能力和速度,都无关紧要。效果是一样的

  • 我之所以这样说,是因为有很多帖子都是由无知的人写的,他们认为这就是记录ID在某种程度上优于关系键的确切原因

  • 关键是,键或记录ID将迁移到需要引用的任何位置

  • 其次,如果必须更改键或记录ID的值,那么必须更改它。以下是符合OLTP标准的方法。请注意,高端供应商不允许“级联更新”

    • 写一个程序。Foo_UpdateCascade_tr@ID,其中Foo是表名

    • 开始交易

    • 第一次插入—从旧行中选择父表中具有新键或RID值的新行

    • 其次,对于自上而下工作的所有子表,使用新键或RID值从旧行中插入并选择新行

    • 第三,从下至上删除子表中具有旧键或RID值的行

    • 最后,删除父表中具有旧键或RID值的行

    • 提交事务

    其他答案是什么 其他答案是不正确的

    • 在更新所需行(父项加上所有子项)后禁用约束,然后启用约束,这不是一个人在在线生产环境中希望继续工作时会做的事情。该建议适用于单用户数据库

    • 需要更改键或RID的值并不表示存在设计缺陷。这是一种普通的需要。通过选择稳定(非静态)的关键点可以缓解这种情况。它可以减轻,但不能消除

    • 替代自然密钥的代理不会产生任何影响。在您给出的示例中,“key”是一个代理项。它需要更新

      • 拜托,只是代理,没有“代理键”这样的东西,因为每个词都互相矛盾。要么是一个键(由数据组成),要么不是。代理项不是由数据组成的,它是显式的非数据。它没有键的任何属性
    • 级联所有必需的更改并没有什么“棘手”的地方。请参阅上述步骤

    • 没有什么可以阻止宇宙的变化。它改变了。处理它。由于数据库是关于宇宙的事实的集合,当宇宙发生变化时,数据库将不得不改变。这是大城市的生活,不适合新手

    • 人们结婚和刺猬被埋都不是问题(尽管有这样的例子表明这是一个问题)。因为我们不使用名称作为键。我们使用小型、稳定的标识符,例如用于识别宇宙中的数据的标识符

      • 名称、描述等在一行中存在一次。密钥存在于已迁移的任何位置。如果“键”是一个RID,那么RID也存在于它被迁移的任何地方
    • 不要更新PK!这是我最近读到的第二个最搞笑的东西。添加一个新列是最重要的

      • 如果您确信
        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;