Удаление идентификатора из столбца таблицы


У нас есть таблица 5GB (почти 500 миллионов строк), и мы хотим удалить свойство identity на одном из столбцов, но когда мы пытаемся сделать это через SSMS - это тайм-аут.

можно ли это сделать через T-SQL?

9 87

9 ответов:

вы не можете удалить IDENTITY спецификация после установки.

удалить весь столбец:

ALTER TABLE yourTable
DROP COLUMN yourCOlumn;

информация о ALTER TABLE здесь

если нужно сохранить данные, но удалить

это становится грязным с внешними и первичными ключевыми ограничениями, так что вот несколько сценариев, которые помогут вам на вашем пути:

сначала создайте дубликат столбца с временным именем:

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

далее, получите имя вашего ограничения первичного ключа:

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

теперь попробуйте удалить ограничение первичного ключа для столбца:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;

если у вас есть внешние ключи, это не удастся, так что если так отбросить ограничения внешнего ключа. СЛЕДИТЕ ЗА ТЕМ, КАКИЕ ТАБЛИЦЫ ВЫ ЗАПУСКАЕТЕ ЭТО ДЛЯ ТОГО, ЧТОБЫ ВЫ МОГЛИ ДОБАВИТЬ ОГРАНИЧЕНИЯ ПОЗЖЕ!!!

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

после удаления всех ограничений внешнего ключа вы сможете удалить ограничение PK, удалить этот столбец, переименовать столбец temp и добавить ограничение PK в этот столбец:

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;

наконец, добавьте ограничения FK обратно в:

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

Эль Фин!

если вы хотите сделать это без добавления и заполнения нового столбца,без переупорядочивания столбцов и практически без простоев поскольку данные в таблице не меняются, давайте сделаем некоторые волшебные функции с разделением (но поскольку разделы не используются, вам не нужна Enterprise edition):

  1. удалите все внешние ключи, которые указывают на эту таблицу
  2. скрипт таблицы, которая будет создана; переименовать все например, 'MyTable2', 'MyIndex2' и др. Удалите спецификацию идентификации.
  3. теперь у вас должно быть две "идентичные"таблицы, одна полная, другая пустая без идентификатора.
  4. выполнить ALTER TABLE [Original] SWITCH TO [Original2]
  5. теперь ваша исходная таблица будет пустой, а новый будет иметь данные. Вы переключили метаданные для двух таблиц (мгновенный).
  6. отбросьте оригинал (теперь-пустая таблица),exec sys.sp_rename чтобы переименовать различные объекты схемы обратно в исходные имена, и затем вы можете воссоздать свои внешние ключи.

например, дано:

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';

вы можете сделать следующее:

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

у меня просто была такая же проблема. 4 заявления в SSMS вместо использования GUI, и это было очень быстро.

  • создать новый столбец

    alter table users add newusernum int;

  • скопировать значения через

    update users set newusernum=usernum;

  • удалить старую колонку

    alter table users drop column usernum;

  • переименовать новый столбец в старое имя столбца

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

следующий скрипт удаляет поле Identity для столбца с именем 'Id'

надеюсь, что это помогает.

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

ниже код работает как хорошо,когда мы не знаем имя столбца идентификаторов.

и хотите скопировать данные в новую временную таблицу, например Invoice_DELETED. и в следующий раз мы используем: вставить в Invoice_DELETED выберите * из счета-фактуры, где ...

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

особая благодарность 'Andriy M'

для более подробного объяснения см.: https://dba.stackexchange.com/a/138345/101038

только для тех, у кого есть та же проблема, что и у меня. Если вы просто хотите сделать некоторые вставки только один раз вы можете сделать что-то подобное.

допустим у вас есть таблица с двумя столбцами

ID Identity (1,1) | Name Varchar

и хотите вставить строку с идентификатором = 4. Таким образом, вы переустановили его на 3, так что следующий-4

DBCC CHECKIDENT([YourTable], RESEED, 3)

сделать вставки

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

и верните свое семя обратно к самому высокому идентификатору, предположим, что это 15

DBCC CHECKIDENT([YourTable], RESEED, 15)

готово!

У меня было такое же требование, и вы могли бы попробовать этот способ, который я лично рекомендую вам, пожалуйста, вручную создайте yourtable и общий сценарий, и то, что я сделал ниже, было переименовать старое имя таблицы, а также его ограничить для резервного копирования.

=============================

            /* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
            BEGIN TRANSACTION

            SET QUOTED_IDENTIFIER ON
            SET ARITHABORT ON
            SET NUMERIC_ROUNDABORT OFF
            SET CONCAT_NULL_YIELDS_NULL ON
            SET ANSI_NULLS ON
            SET ANSI_PADDING ON
            SET ANSI_WARNINGS ON
            COMMIT
            BEGIN TRANSACTION
            GO
            ALTER TABLE dbo.SI_Provider_Profile
                DROP CONSTRAINT DF_SI_Provider_Profile_SIdtDateTimeStamp
            GO
            ALTER TABLE dbo.SI_Provider_Profile
                DROP CONSTRAINT DF_SI_Provider_Profile_SIbHotelPreLoaded
            GO
            CREATE TABLE dbo.Tmp_SI_Provider_Profile
                (
                SI_lProvider_Profile_ID int NOT NULL,
                SI_lSerko_Integrator_Token_ID int NOT NULL,
                SI_sSerko_Integrator_Provider varchar(50) NOT NULL,
                SI_sSerko_Integrator_Profile varchar(50) NOT NULL,
                SI_dtDate_Time_Stamp datetime NOT NULL,
                SI_lProvider_ID int NULL,
                SI_sDisplay_Name varchar(10) NULL,
                SI_lPurchased_From int NULL,
                SI_sProvider_UniqueID varchar(255) NULL,
                SI_bHotel_Pre_Loaded bit NOT NULL,
                SI_sSiteName varchar(255) NULL
                )  ON [PRIMARY]
            GO
            ALTER TABLE dbo.Tmp_SI_Provider_Profile SET (LOCK_ESCALATION = TABLE)
            GO
            ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
                DF_SI_Provider_Profile_SIdtDateTimeStamp DEFAULT (getdate()) FOR SI_dtDate_Time_Stamp
            GO
            ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
                DF_SI_Provider_Profile_SIbHotelPreLoaded DEFAULT ((0)) FOR SI_bHotel_Pre_Loaded
            GO
            IF EXISTS(SELECT * FROM dbo.SI_Provider_Profile)
                 EXEC('INSERT INTO dbo.Tmp_SI_Provider_Profile (SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName)
                    SELECT SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName FROM dbo.SI_Provider_Profile WITH (HOLDLOCK TABLOCKX)')
            GO

            -- Rename the primary key constraint or unique key In SQL Server constraints such as primary keys or foreign keys are objects in their own right, even though they are dependent upon the "containing" table.
            EXEC sp_rename 'dbo.SI_Provider_Profile.PK_SI_Provider_Profile', 'PK_SI_Provider_Profile_Old';
            GO
            -- backup old table in case of 
            EXECUTE sp_rename N'dbo.SI_Provider_Profile', N'SI_Provider_Profile_Old', 'OBJECT'
            GO

            EXECUTE sp_rename N'dbo.Tmp_SI_Provider_Profile', N'SI_Provider_Profile', 'OBJECT'
            GO

            ALTER TABLE dbo.SI_Provider_Profile ADD CONSTRAINT
                PK_SI_Provider_Profile PRIMARY KEY NONCLUSTERED 
                (
                SI_lProvider_Profile_ID
                ) WITH( PAD_INDEX = OFF, FILLFACTOR = 90, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

            GO
            COMMIT TRANSACTION

=============================

ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'

однако приведенный выше код работает только в том случае, если нет отношения первичного внешнего ключа