لقد أدرجت سجلات في جدول قاعدة بيانات SQL Server. يحتوي الجدول على مفتاح أساسي محدد ويتم تعيين هوية هوية الزيادة التلقائية على "نعم". يتم ذلك في المقام الأول لأنه في SQL Azure ، يجب أن يكون لكل جدول مفتاح وهوية أساسية محددة.
ولكن بما أن عليّ حذف بعض السجلات من الجدول ، فسيتم إزعاج أصل الهوية الخاص بهذه الجداول وسيزعج عمود الفهرس (الذي يتم إنشاؤه تلقائيًا بزيادة قدرها 1).
كيف يمكنني إعادة تعيين عمود الهوية بعد أن قمت بحذف السجلات بحيث يحتوي العمود على تسلسل بترتيب رقمي تصاعدي؟
لا يتم استخدام عمود الهوية كمفتاح خارجي في أي مكان في قاعدة البيانات.
يتم استخدام الأمر 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 بمسح الأشياء في وثائقها الخاصة ، هي إجراء اختبارات فعلية قبل الاستخدام.
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO
حيث 0 هي identity
Start value
تجدر الإشارة إلى أنه إذا تمت إزالة 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
(مرتبط أعلاه) للحصول على معلومات إضافية حول القيود ، إلخ.
على الرغم من أن معظم الإجابات تقترح 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)
سيؤدي هذا إلى التحقق من الجدول وإعادة التعيين إلى المعرف التالي.
جربت @anil shahs
إجابة وإعادة تعيين الهوية. ولكن عندما تم إدراج صف جديد ، حصلت على identity = 2
. بدلاً من ذلك ، قمت بتغيير بناء الجملة إلى:
DELETE FROM [TestTable]
DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO
ثم سوف تحصل على الصف الأول الهوية = 1.
على الرغم من أن معظم الإجابات تقترح RESEED
على 0
، وبينما يرى البعض هذا خطأ في الجداول TRUNCATED
، فإن لدى Microsoft حلاً يستبعد ID
DBCC CHECKIDENT ('[TestTable]', RESEED)
سيؤدي هذا إلى التحقق من الجدول وإعادة التعيين إلى ID
التالي. لقد كان هذا متاحًا منذ MS SQL 2005 إلى الوقت الحالي.
jacob
DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)
عملت لي ، واضطررت فقط لمسح جميع الإدخالات أولاً من الجدول ، ثم أضفت أعلاه في نقطة انطلاق بعد الحذف. الآن كلما قمت بحذف إدخال مأخوذ من هناك.
إصدار 2 القيادة يمكن أن تفعل الخدعة
DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)
الأول يعيد تعيين الهوية إلى الصفر ، وسيحدد التالي القيمة التالية المتاحة - jacob
هذا سؤال شائع والإجابة هي نفسها دائمًا: لا تفعل ذلك. يجب التعامل مع قيم الهوية على أنها عشوائية ، وبالتالي لا يوجد ترتيب "صحيح".
يُفضل الجدول Truncate
لأنه يمسح السجلات ويعيد ضبط العداد ويستعيد مساحة القرص.
يجب استخدام Delete
و CheckIdent
فقط عندما تمنعك المفاتيح الخارجية من الاقتطاع
إعادة تعيين عمود الهوية بمعرف جديد ...
DECLARE @MAX INT
SELECT @MAX=ISNULL(MAX(Id),0) FROM [TestTable]
DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
قم بتشغيل هذا البرنامج النصي لإعادة تعيين عمود الهوية. سوف تحتاج إلى إجراء تغييرين. استبدل 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
استخدم هذا الإجراء المخزن:
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 لا تستطيع الحصول على هذه الأشياء بشكل صحيح. لقد اكتشفت ذلك لأن لدي ملف نصي يملأ الجداول المرجعية التي أشغلها أحيانًا بعد إعادة إنشاء الجداول وأحيانًا عندما يتم إنشاء الجداول بالفعل.
للحصول على صفوف 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
أنا استخدم البرنامج النصي التالي للقيام بذلك. يوجد سيناريو واحد فقط ينتج عنه "خطأ" ، وهو إذا قمت بحذف جميع الصفوف من الجدول ، وتم تعيين 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)
;
DBCC CHECKIDENT (<TableName>, reseed, 0)
سيؤدي هذا إلى تعيين قيمة الهوية الحالية إلى 0.
عند إدخال القيمة التالية ، يتم زيادة قيمة الهوية إلى 1.