it-swarm.asia

إعادة تعيين هوية الهوية بعد حذف السجلات في SQL Server

لقد أدرجت سجلات في جدول قاعدة بيانات SQL Server. يحتوي الجدول على مفتاح أساسي محدد ويتم تعيين هوية هوية الزيادة التلقائية على "نعم". يتم ذلك في المقام الأول لأنه في SQL Azure ، يجب أن يكون لكل جدول مفتاح وهوية أساسية محددة.

ولكن بما أن عليّ حذف بعض السجلات من الجدول ، فسيتم إزعاج أصل الهوية الخاص بهذه الجداول وسيزعج عمود الفهرس (الذي يتم إنشاؤه تلقائيًا بزيادة قدرها 1).

كيف يمكنني إعادة تعيين عمود الهوية بعد أن قمت بحذف السجلات بحيث يحتوي العمود على تسلسل بترتيب رقمي تصاعدي؟

لا يتم استخدام عمود الهوية كمفتاح خارجي في أي مكان في قاعدة البيانات.

582
Romil N

يتم استخدام الأمر DBCC CHECKIDENT management لإعادة تعيين عداد الهوية. بناء جملة الأمر هو:

DBCC CHECKIDENT (table_name [, { NORESEED | { RESEED [, new_reseed_value ]}}])
[ WITH NO_INFOMSGS ]

مثال:

DBCC CHECKIDENT ('[TestTable]', RESEED, 0);
GO

لم يكن مدعومًا في الإصدارات السابقة من قاعدة بيانات SQL Azure ، لكنه معتمد الآن.


يرجى ملاحظة أن الوسيطة new_reseed_value متنوعة في إصدارات SQL Server وفقًا للوثائق :

إذا كانت هناك صفوف في الجدول ، فسيتم إدراج الصف التالي بقيمة new_reseed_value. في الإصدار SQL Server 2008 R2 والإصدارات السابقة ، يستخدم الصف التالي المدرج new_reseed_value + قيمة الزيادة الحالية.

ومع ذلك ، أجد أن هذه المعلومات مضللة (خطأ بسيط في الواقع) لأن السلوك الملاحظ يشير إلى أن SQL Server 2012 على الأقل لا يزال يستخدم new_reseed_value + منطق قيمة الزيادة الحالية. تتعارض Microsoft حتى مع Example C الخاص بها الموجود في نفس الصفحة:

فرض قيمة الهوية الحالية على قيمة جديدة

يفرض المثال التالي قيمة الهوية الحالية في عمود AddressTypeID في جدول AddressType على قيمة 10. لأن الجدول يحتوي على صفوف موجودة ، سيستخدم الصف التالي المدرج 11 كقيمة ، أي قيمة الزيادة الحالية الجديدة المحددة لـ قيمة العمود زائد 1.

USE AdventureWorks2012;  
GO  
DBCC CHECKIDENT ('Person.AddressType', RESEED, 10);  
GO

ومع ذلك ، كل هذا يترك خيارًا لسلوك مختلف على إصدارات SQL Server الأحدث. أعتقد أن الطريقة الوحيدة للتأكد ، حتى تقوم Microsoft بمسح الأشياء في وثائقها الخاصة ، هي إجراء اختبارات فعلية قبل الاستخدام.

952
Petr Abdulin
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO

حيث 0 هي identity Start value

193
anil shah

تجدر الإشارة إلى أنه إذا تمت إزالة IF all / من البيانات من الجدول عبر DELETE (أي لا توجد جملة WHERE) ، فطالما سمحت) أذونات بذلك ، و b) بالرجوع إلى الجدول (الذي يبدو أن هذا هو الحال هنا) ، سيفضل استخدام TRUNCATE TABLE لأنه يعمل بشكل أكبر على DELETE و / إعادة تعيين بذرة IDENTITY في نفس الوقت. التفاصيل التالية مأخوذة من صفحة MSDN لـ TRUNCATE TABLE :

مقارنة ببيان DELETE ، يحتوي TRUNCATE TABLE على المزايا التالية:

  • يتم استخدام مساحة سجل معاملات أقل.

    عبارة DELETE تزيل الصفوف واحدًا تلو الآخر وتسجل إدخالًا في سجل المعاملات لكل صف محذوف. يزيل TRUNCATE TABLE البيانات عن طريق إلغاء تخصيص صفحات البيانات المستخدمة لتخزين بيانات الجدول ويسجل فقط تخصيصات الصفحة في سجل المعاملات.

  • عادة ما تستخدم أقفال أقل.

    عند تنفيذ عبارة DELETE باستخدام قفل صف ، يتم تأمين كل صف في الجدول للحذف. يقوم TRUNCATE TABLE دائمًا بإغلاق الجدول (بما في ذلك تأمين المخطط (SCH-M)) والصفحة ولكن ليس كل صف.

  • بدون استثناء ، يتم ترك صفحات صفرية في الجدول.

    بعد تنفيذ عبارة DELETE ، لا يزال الجدول يحتوي على صفحات فارغة. على سبيل المثال ، لا يمكن إلغاء تخصيص الصفحات الفارغة في كومة الذاكرة المؤقتة دون قفل جدول (LCK_M_X) خاص على الأقل. إذا كانت عملية الحذف لا تستخدم قفل الجدول ، فسيحتوي الجدول (الكومة) على العديد من الصفحات الفارغة. بالنسبة إلى الفهارس ، يمكن أن تترك عملية الحذف الصفحات الفارغة وراءها ، على الرغم من أنه سيتم إلغاء تخصيص هذه الصفحات بسرعة من خلال عملية تنظيف الخلفية.

إذا كان الجدول يحتوي على عمود هوية ، تتم إعادة تعيين العداد لهذا العمود إلى القيمة الأولية المحددة للعمود. إذا لم يتم تعريف أي بذرة ، فسيتم استخدام القيمة الافتراضية 1. للاحتفاظ عداد الهوية ، استخدم DELETE بدلاً من ذلك.

لذلك ما يلي:

DELETE FROM [MyTable];
DBCC CHECKIDENT ('[MyTable]', RESEED, 0);

يصبح مجرد:

TRUNCATE TABLE [MyTable];

يرجى الاطلاع على وثائق TRUNCATE TABLE (مرتبط أعلاه) للحصول على معلومات إضافية حول القيود ، إلخ.

74
Solomon Rutzky

على الرغم من أن معظم الإجابات تقترح RESEED إلى 0 ، ولكن في كثير من الأحيان نحتاج فقط إلى إعادة إرسال المعرف التالي المتاح

declare @max int
select @max=max([Id])from [TestTable]
if @max IS NULL   //check when max is returned as null
  SET @max = 0
DBCC CHECKIDENT ('[TestTable]', RESEED,@max)

سيؤدي هذا إلى التحقق من الجدول وإعادة التعيين إلى المعرف التالي.

64
Atal Kishore

جربت @anil shahs إجابة وإعادة تعيين الهوية. ولكن عندما تم إدراج صف جديد ، حصلت على identity = 2. بدلاً من ذلك ، قمت بتغيير بناء الجملة إلى:

DELETE FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO

ثم سوف تحصل على الصف الأول الهوية = 1.

58
Mikael Engver

على الرغم من أن معظم الإجابات تقترح RESEED على 0 ، وبينما يرى البعض هذا خطأ في الجداول TRUNCATED ، فإن لدى Microsoft حلاً يستبعد ID

DBCC CHECKIDENT ('[TestTable]', RESEED)

سيؤدي هذا إلى التحقق من الجدول وإعادة التعيين إلى ID التالي. لقد كان هذا متاحًا منذ MS SQL 2005 إلى الوقت الحالي.

https://msdn.Microsoft.com/en-us/library/ms176057.aspx

15
SollyM

jacob

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

عملت لي ، واضطررت فقط لمسح جميع الإدخالات أولاً من الجدول ، ثم أضفت أعلاه في نقطة انطلاق بعد الحذف. الآن كلما قمت بحذف إدخال مأخوذ من هناك.

5
epic

إصدار 2 القيادة يمكن أن تفعل الخدعة

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

الأول يعيد تعيين الهوية إلى الصفر ، وسيحدد التالي القيمة التالية المتاحة - jacob

5
jacob

هذا سؤال شائع والإجابة هي نفسها دائمًا: لا تفعل ذلك. يجب التعامل مع قيم الهوية على أنها عشوائية ، وبالتالي لا يوجد ترتيب "صحيح".

5
Ben Thul

يُفضل الجدول Truncate لأنه يمسح السجلات ويعيد ضبط العداد ويستعيد مساحة القرص.

يجب استخدام Delete و CheckIdent فقط عندما تمنعك المفاتيح الخارجية من الاقتطاع

4
Dyna Dave

إعادة تعيين عمود الهوية بمعرف جديد ...

DECLARE @MAX INT
SELECT @MAX=ISNULL(MAX(Id),0) FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
4
Mukesh Pandey

قم بتشغيل هذا البرنامج النصي لإعادة تعيين عمود الهوية. سوف تحتاج إلى إجراء تغييرين. استبدل tableXYZ بأي جدول تحتاج إلى تحديثه. أيضًا ، يجب إسقاط اسم عمود الهوية من الجدول المؤقت. كان هذا فوريًا على طاولة بها 35000 صف و 3 أعمدة. من الواضح ، قم بنسخ الجدول احتياطيًا وجرب هذا أولاً في بيئة اختبار.


select * 
into #temp
From tableXYZ

set identity_insert tableXYZ ON

truncate table tableXYZ

alter table #temp drop column (nameOfIdentityColumn)

set identity_insert tableXYZ OFF

insert into tableXYZ
select * from #temp
2
Matthew Baic

استخدم هذا الإجراء المخزن:

IF (object_id('[dbo].[pResetIdentityField]') IS NULL)
  BEGIN
    EXEC('CREATE PROCEDURE [dbo].[pResetIdentityField] AS SELECT 1 FROM DUMMY');
  END
GO

SET  ANSI_NULLS ON
GO
SET  QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[pResetIdentityField]
  @pSchemaName NVARCHAR(1000)
, @pTableName NVARCHAR(1000) AS
DECLARE @max   INT;
DECLARE @fullTableName   NVARCHAR(2000) = @pSchemaName + '.' + @pTableName;

DECLARE @identityColumn   NVARCHAR(1000);

SELECT @identityColumn = c.[name]
FROM sys.tables t
     INNER JOIN sys.schemas s ON t.[schema_id] = s.[schema_id]
     INNER JOIN sys.columns c ON c.[object_id] = t.[object_id]
WHERE     c.is_identity = 1
      AND t.name = @pTableName
      AND s.[name] = @pSchemaName

IF @identityColumn IS NULL
  BEGIN
    RAISERROR(
      'One of the following is true: 1. the table you specified doesn''t have an identity field, 2. you specified an invalid schema, 3. you specified an invalid table'
    , 16
    , 1);
    RETURN;
  END;

DECLARE @sqlString   NVARCHAR(MAX) = N'SELECT @maxOut = max(' + @identityColumn + ') FROM ' + @fullTableName;

EXECUTE sp_executesql @stmt = @sqlString, @params = N'@maxOut int OUTPUT', @maxOut = @max OUTPUT

IF @max IS NULL
  SET @max = 0

print(@max)

DBCC CHECKIDENT (@fullTableName, RESEED, @max)
go

--exec pResetIdentityField 'dbo', 'Table'

مجرد إعادة النظر في جوابي. صادفت سلوكًا غريبًا في sql server 2008 r2 يجب أن تكون على دراية به.

drop table test01

create table test01 (Id int identity(1,1), descr nvarchar(10))

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

delete from test01

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

التحديد الأول ينتج 0, Item 1.

ينتج الثاني 1, Item 1. إذا قمت بتنفيذ إعادة التعيين مباشرة بعد إنشاء الجدول ، فستكون القيمة التالية هي 0. بصراحة ، لست متفاجئًا بأن Microsoft لا تستطيع الحصول على هذه الأشياء بشكل صحيح. لقد اكتشفت ذلك لأن لدي ملف نصي يملأ الجداول المرجعية التي أشغلها أحيانًا بعد إعادة إنشاء الجداول وأحيانًا عندما يتم إنشاء الجداول بالفعل.

1
costa

للحصول على صفوف DELETE كاملة وإعادة تعيين عدد IDENTITY ، استخدم هذا (SQL Server 2008 R2)

USE mydb

-- ##################################################################################################################
-- DANGEROUS!!!! USE WITH CARE
-- ##################################################################################################################

DECLARE
  db_cursor CURSOR FOR
    SELECT TABLE_NAME
      FROM INFORMATION_SCHEMA.TABLES
     WHERE TABLE_TYPE = 'BASE TABLE'
       AND TABLE_CATALOG = 'mydb'

DECLARE @tblname VARCHAR(50)
SET @tblname = ''

OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tblname

WHILE @@FETCH_STATUS = 0
BEGIN
  IF CHARINDEX('mycommonwordforalltablesIwanttodothisto', @tblname) > 0
    BEGIN
      EXEC('DELETE FROM ' + @tblname)
      DBCC CHECKIDENT (@tblname, RESEED, 0)
    END

  FETCH NEXT FROM db_cursor INTO @tblname
END

CLOSE db_cursor
DEALLOCATE db_cursor
GO
0
Fandango68

أنا استخدم البرنامج النصي التالي للقيام بذلك. يوجد سيناريو واحد فقط ينتج عنه "خطأ" ، وهو إذا قمت بحذف جميع الصفوف من الجدول ، وتم تعيين IDENT_CURRENT حاليًا على 1 ، أي أنه يوجد صف واحد فقط في الجدول لتبدأ.

DECLARE @maxID int = (SELECT MAX(ID) FROM dbo.Tbl)
;

IF @maxID IS NULL
    IF (SELECT IDENT_CURRENT('dbo.Tbl')) > 1
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 0)
    ELSE
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 1)
    ;
ELSE
    DBCC CHECKIDENT ('dbo.Tbl', RESEED, @maxID)
;
0
Chris Mack
DBCC CHECKIDENT (<TableName>, reseed, 0)

سيؤدي هذا إلى تعيين قيمة الهوية الحالية إلى 0.

عند إدخال القيمة التالية ، يتم زيادة قيمة الهوية إلى 1.

0
Bimzee