Cómo actualizar la clave principal

Aquí está mi problema: tengo 2 tablas:

  1. TRABAJADOR, con columnas |ID|OTHER_STAF| , donde ID es clave principal
  2. FIRM, con columnas |FPK|ID|SOMETHING_ELSE| , donde la combinación FPK e ID hacen la clave primaria, y también ID es una clave foránea referenciada a WORKER.ID (no nula, y debe tener el mismo valor que en WORKER).

Quiero hacer que el procedimiento almacenado UPDATE_ID_WORKER, donde me gustaría cambiar el valor de ID específico en WORKER, y también en todas las instancias de valor específico de ID en FIRM.

procedimiento almacenado:

…….. @carné de identidad .. ???? ……..

En realidad, no debería hacer esto, sino insertar en un nuevo registro y actualizarlo de esa manera.
Pero, si realmente lo necesita, puede hacer lo siguiente:

  • Desactivar la aplicación de restricciones FK temporalmente (por ejemplo, ALTER TABLE foo WITH NOCHECK CONSTRAINT ALL )
  • Luego actualiza tu PK
  • A continuación, actualice sus FK para que coincida con el cambio PK
  • Finalmente, habilite las restricciones de FK.

Primero, elegimos columnas de datos estables (no estáticas) para formar una clave principal, precisamente porque actualizar claves en una base de datos relacional (en la que las referencias son por clave) es algo que deseamos evitar.

  1. Para este problema, no importa si la clave es una clave relacional (“creada a partir de los datos”), y por lo tanto tiene integridad relacional, potencia y velocidad, o si la “clave” es una identificación de registro, sin ninguna de esa Integridad Relacional, Poder y Velocidad. El efecto es el mismo.

  2. Lo afirmo porque hay muchas publicaciones de los desorientados, que sugieren que esta es la razón exacta por la que los ID de registro son de alguna manera mejores que las claves relacionales.

  3. El punto es que la clave o ID de registro se migra a cualquier lugar donde se requiera una referencia.

En segundo lugar, si tiene que cambiar el valor de la clave o la identificación del registro, debe cambiarlo. Aquí está el método compatible con el estándar OLTP. Tenga en cuenta que los proveedores de gama alta no permiten la “actualización en cascada”.

  • Escribe un proc. Foo_UpdateCascade_tr @ID, donde Foo es el nombre de la tabla

  • Comience una transacción

  • Primero INSERT-SELECT una nueva fila en la tabla padre, desde la fila anterior, con la nueva clave o valor RID

  • En segundo lugar, para todas las tablas secundarias, trabajando de arriba a abajo, INSERT-SELECT las filas nuevas, de las filas anteriores, con la nueva clave o valor RID

  • En tercer lugar, ELIMINE las filas en las tablas secundarias que tienen el valor clave o RID anterior, trabajando de abajo hacia arriba

  • Por último, BORRAR la fila en la tabla padre que tiene la clave anterior o el valor RID

  • Confirmar la transacción

Re the Other Answers

Las otras respuestas son incorrectas.

  • Desactivar restricciones y luego habilitarlas, después de ACTUALIZAR las filas requeridas (principal más todos los hijos) no es algo que una persona haría en un entorno de producción en línea, si desea permanecer empleado. Ese consejo es bueno para bases de datos de usuario único.

  • La necesidad de cambiar el valor de una clave o RID no es indicativo de un defecto de diseño. Es una necesidad ordinaria. Esto se mitiga eligiendo Claves estables (no estáticas). Se puede mitigar, pero no se puede eliminar.

  • Un suplente que sustituye una Clave natural, no hará ninguna diferencia. En el ejemplo que ha dado, la “clave” es un sustituto. Y necesita ser actualizado.

    • Por favor, sustitúyase, no existe una “clave sustituta”, porque cada palabra contradice a la otra. O bien es una clave (compuesta de los datos) xo no lo es. Un sustituto no se compone de los datos, es explícitamente no data . No tiene ninguna de las propiedades de una clave.
  • No hay nada “complicado” sobre la conexión en cascada de todos los cambios requeridos. Consulte los pasos dados arriba.

  • No hay nada que pueda evitarse en el cambio del universo. Cambia. Tratar con él. Y dado que la base de datos es una colección de hechos sobre el universo, cuando el universo cambie, la base de datos tendrá que cambiar. Así es la vida en la gran ciudad, no es para nuevos jugadores.

  • Las personas que se casan y los erizos que se entierran no son un problema (a pesar de que se usan estos ejemplos para sugerir que es un problema). Porque no usamos Nombres como Claves. Usamos identificadores pequeños y estables, como los que se usan para identificar los datos en el universo.

    • Los nombres, descripciones, etc., existen una vez, en una fila. Las claves existen dondequiera que hayan sido migradas. Y si la “clave” es un RID, entonces el RID también existe allí donde se haya migrado.
  • ¡No actualice el PK! es la segunda cosa más hilarante que he leído en mucho tiempo. Agregar una nueva columna es lo máximo.

Si está seguro de que este cambio es adecuado para el entorno en el que está trabajando: establezca las condiciones FK en las tablas secundarias para ACTUALIZAR CASCADING.

Por ejemplo, si usa SSMS como GUI:

  1. haga clic derecho en la tecla
  2. seleccione Modificar
  3. Doblar ‘INSERTAR Y ACTUALIZAR Específico’
  4. Para ‘Actualizar regla’, seleccione Cascada.
  5. Cierre el cuadro de diálogo y guarde la clave.

Cuando actualice un valor en la columna PK en su tabla principal, las referencias FK en las otras tablas se actualizarán para apuntar al nuevo valor, preservando la integridad de los datos.

Cuando considere necesario actualizar un valor de clave principal, así como todas las claves foráneas coincidentes, entonces es necesario reparar todo el diseño.

Es complicado conectar en cascada todos los cambios de claves foráneas necesarios. Es una práctica recomendada nunca actualizar la clave principal, y si lo considera necesario, debe usar una Surrogate Primary Key , que no es una clave derivada de los datos de la aplicación. Como resultado, su valor no está relacionado con la lógica comercial y nunca necesita cambiar (y debe ser invisible para el usuario final). Luego puede actualizar y visualizar alguna otra columna.

por ejemplo:

 BadUserTable UserID varchar(20) primary key --user last name other columns... 

Cuando creas muchas tablas que tienen un FK a UserID, para rastrear todo lo que el usuario ha trabajado, pero ese usuario se casa y quiere una ID que coincida con su nuevo apellido, no tienes suerte.

 GoodUserTable UserID int identity(1,1) primary key UserLogin varchar(20) other columns.... 

ahora FK la clave primaria sustituta para todas las demás tablas, y muestra UserLogin cuando sea necesario, les permite iniciar sesión utilizando ese valor, y cuando tienen que cambiarlo, lo cambia en una columna de una sola fila.

No actualice la clave principal . Podría causar muchos problemas para mantener intactos sus datos, si tiene otras tablas que lo hagan referencia.

Idealmente, si desea un campo único que se pueda actualizar, cree un nuevo campo.

Puede usar esta función recursiva para generar la secuencia de comandos T-SQL necesaria.

 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; 
Intereting Posts