2011-11-22 24 views
76

Tenemos una tabla de 5GB (casi 500 millones de filas) y queremos eliminar la propiedad de identidad en una de las columnas, pero cuando intentamos hacer esto a través de SSMS, se agota el tiempo.Eliminar identidad de una columna en una tabla

¿Se puede hacer esto a través de T-SQL?

+0

¿Puedes publicar el esquema de la tabla aquí? –

+0

Estoy seguro de que hay excelentes razones por las que SQL Server no admite eliminar una propiedad de identidad de una columna mediante una simple instrucción ALTER TABLE ..., pero de todos modos me entristece que ese sea el caso. –

Respuesta

95

Una vez configurado, no se puede eliminar una especificación IDENTITY.

Para eliminar toda la columna:

ALTER TABLE yourTable 
DROP COLUMN yourCOlumn; 

Información sobre ALTER TABLE aquí

Si necesita mantener los datos, pero quitar la columna IDENTITY, que se necesitan para:

  • Cree una nueva columna
  • Transfiera los datos de la columna existente tt o la nueva columna
  • Elimine la columna existente IDENTITY.
  • Cambiar el nombre de la nueva columna con el nombre original de la columna
+3

puede eliminar una especificación de identidad. De hecho, tuve que hacerlo ayer usando SSMS aunque no en 500 millones de filas. – Simon

+20

@simon si escribe los cambios, verá que SSMS está creando una copia de la tabla sin la propiedad de identidad. –

+3

Solo quiero agregar para cambiar el nombre de la nueva columna al nombre de la columna original. Además, si esta columna 'identity' se usa como parte de una' foreign key' en otra tabla, primero tendrá que soltar las restricciones, luego tomar medidas como @AdamWenger mencionó sobre la eliminación de la identidad 'attribute/property' .. También puede consultar este enlace para obtener más detalles sobre la eliminación únicamente del atributo: http://blog.sqlauthority.com/2009/05/03/sql-server-add-or-remove-identity-property-on- columna/.. ¡Buena suerte! – Nonym

46

Esto se complica con restricciones de clave externa y primaria, así que aquí tiene algunos scripts para ayudarle en su camino:

En primer lugar, cree una columna duplicado con un nombre temporal:

alter table yourTable add tempId int NOT NULL default -1; 
update yourTable set tempId = id; 

a continuación, obtener el nombre de la restricción de clave primaria:

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'yourTable'; 

Ahora intente quitar la restricción de clave principal para su columna:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id; 

Si tiene claves foráneas, se producirá un error, por lo que si por lo deje caer las restricciones de clave externa. MANTENGA LA PISTA DE CUALES TABLAS USTED CORRA PARA QUE PUEDA AGREGAR LAS RESTRICCIONES DE INMEDIATO.

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'otherTable'; 
alter table otherTable drop constraint fk_otherTable_yourTable; 
commit; 
.. 

vez que todos sus restricciones de claves foráneas se han eliminado, usted será capaz de eliminar la restricción de PK, la caída de esa columna, cambiar el nombre de la columna de temperatura, y añadir la restricción de PK a esa columna:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id; 
alter table yourTable drop column id; 
EXEC sp_rename 'yourTable.tempId', 'id', 'COLUMN'; 
ALTER TABLE yourTable ADD CONSTRAINT PK_yourTable_id PRIMARY KEY (id) 
commit; 

por último, añadir las limitaciones FK vuelta en:

alter table otherTable add constraint fk_otherTable_yourTable foreign key (yourTable_id) references yourTable(id); 
.. 

el fin!

+0

preste atención a su versión de servidor sql, probé en el servidor sql azul, no todas las operaciones aquí son compatibles con la versión azul sql. – dasons

+0

¡Gracias por la respuesta! ¡Me ayudo mucho! Solo debe agregar una verificación para los índices que hacen referencia a la columna. Algo así como: 'Select t.name 'Tabla', i.name 'Índice', c.name 'Columna', \t i.is_primary_key, \t i.is_unique De sys.tables t Interior Unirse a sys.indexes i On i.object_id = t.object_id Unión interna sys.index_columns ic ON ic.object_id = i.object_id Y i.index_id = ic.index_id Inner Unir sys.columns c ON ic.object_id = c. object_id y ic.column_id = c.column_id Donde t.name = 'tableName' Orden por t.nombre, i.nombre, i.index_id, ic.index_column_id' –

+0

buen truco, me ayudó mucho, pero un punto, quiero mencionar aquí es que, cuando agregamos una nueva columna duplicada como se menciona en el 1er paso, se agrega al final, pero en general queremos que nuestra columna clave principal, es decir Id ser la primera columna en esa tabla. Entonces, ¿hay alguna solución para eso? –

40

Si quieres hacer esto sin añadir y llenar una nueva columna, sin reordenar las columnas, y casi sin tiempo de inactividad porque no hay datos está cambiando en la mesa, vamos a hacer un poco de magia con la funcionalidad de partición (pero ya no se utilizan particiones que no necesita la edición Enterprise):

  1. Retire todas las claves externas que apuntan a esta tabla
  2. escritura la tabla que se creó; renombrar todo, p. 'MyTable2', 'MyIndex2', etc. Elimina la especificación de IDENTIDAD.
  3. Ahora debería tener dos tablas "idénticas", una llena y la otra vacía sin IDENTIDAD.
  4. Ejecutar ALTER TABLE [Original] SWITCH TO [Original2]
  5. Ahora su tabla original estará vacía y la nueva tendrá los datos. Has cambiado los metadatos de las dos tablas (instantáneo).
  6. Suelta el original (tabla ahora vacía), exec sys.sp_rename para cambiar el nombre de los diversos objetos de esquema a los nombres originales, y luego puedes volver a crear tus claves externas.

Por ejemplo, teniendo en cuenta:

CREATE TABLE Original 
(
    Id INT IDENTITY PRIMARY KEY 
, Value NVARCHAR(300) 
); 
CREATE NONCLUSTERED INDEX IX_Original_Value ON Original (Value); 

INSERT INTO Original 
SELECT 'abcd' 
UNION ALL 
SELECT 'defg'; 

Usted puede hacer lo siguiente:

--create new table with no IDENTITY 
CREATE TABLE Original2 
(
    Id INT PRIMARY KEY 
, Value NVARCHAR(300) 
); 
CREATE NONCLUSTERED INDEX IX_Original_Value2 ON Original2 (Value); 

--data before switch 
SELECT 'Original', * 
FROM Original 
UNION ALL 
SELECT 'Original2', * 
FROM Original2; 

ALTER TABLE Original SWITCH TO Original2; 

--data after switch 
SELECT 'Original', * 
FROM Original 
UNION ALL 
SELECT 'Original2', * 
FROM Original2; 

--clean up 
DROP TABLE Original; 
EXEC sys.sp_rename 'Original2.IX_Original_Value2', 'IX_Original_Value', 'INDEX'; 
EXEC sys.sp_rename 'Original2', 'Original', 'OBJECT'; 


UPDATE Original 
SET Id = Id + 1; 

SELECT * 
FROM Original; 
+0

No tengo tiempo para probar esto, pero es bueno saber la próxima vez que realmente necesito dejar una identidad. – CoderDennis

+5

Esta debería ser la respuesta aceptada. Es la única forma real de eliminar una columna de identidad sin migración masiva de datos. – Vaccano

+0

¡Guau! Esto es muy inteligente. –

11

solo tenía este mismo problema. 4 declaraciones en SSMS en lugar de usar la GUI y fue muy rápido.

  • hacer una nueva columna

    alter table users add newusernum int;

  • valores de copia sobre

    update users set newusernum=usernum;

  • gota la columna de edad

    alter table users drop column usernum;

  • Cambiar el nombre de la nueva columna a la edad, nombre de la columna

    EXEC sp_RENAME 'users.newusernum' , 'usernum', 'COLUMN';

7

siguiente secuencia de comandos elimina campo de identidad de una columna llamada 'Id'

espero que ayude.

BEGIN TRAN 
BEGIN TRY 
    EXEC sp_rename '[SomeTable].[Id]', 'OldId'; 

    ALTER TABLE [SomeTable] ADD Id int NULL 

    EXEC ('UPDATE [SomeTable] SET Id = OldId') 

    ALTER TABLE [SomeTable] NOCHECK CONSTRAINT ALL 

    ALTER TABLE [SomeTable] DROP CONSTRAINT [PK_constraintName]; 
    ALTER TABLE [SomeTable] DROP COLUMN OldId 
    ALTER TABLE [SomeTable] ALTER COLUMN [Id] INTEGER NOT NULL 
    ALTER TABLE [SomeTable] ADD CONSTRAINT PK_JobInfo PRIMARY KEY (Id) 

    ALTER TABLE [SomeTable] CHECK CONSTRAINT ALL 

    COMMIT TRAN 
END TRY 
BEGIN CATCH 
    ROLLBACK TRAN 
    SELECT ERROR_MESSAGE() 
END CATCH 
1

código Fuelle de trabajo tan fino, cuando no sabemos la identidad nombre de la columna.

y desea copiar datos en una nueva tabla temporal como Invoice_DELETED. y la próxima vez que usemos: inserte en Invoice_DELETED select * from Invoice donde ...

SELECT t1.* 
INTO Invoice_DELETED 
FROM Invoice t1 
LEFT JOIN Invoice ON 1 = 0 
--WHERE t1.InvoiceID = @InvoiceID 

un agradecimiento especial a

para una explicación más detallada, véase 'Andriy M': https://dba.stackexchange.com/a/138345/101038

0

Sólo para alguien que tiene el mismo problema que yo. Si solo desea hacer algunas inserciones solo una vez, puede hacer algo como esto.

Lets suponga que tiene una tabla con dos columnas

ID Identity (1,1) | Name Varchar 

y desea insertar una fila con el ID = 4. Así que sembrar de nuevo a 3 por lo que el siguiente es 4

DBCC CHECKIDENT([YourTable], RESEED, 3) 

Hacer la inserción

INSERT INTO [YourTable] 
     (Name) 
VALUES ('Client') 

y obtener su semilla de nuevo a la más alta de identificación, vamos a suponer que es de 15

DBCC CHECKIDENT([YourTable], RESEED, 15) 

¡Hecho!

Cuestiones relacionadas