مثالهای عملی از پایه تا حرفهای
ده مثال زیر مستقل طراحی شدهاند. هر نمونه هدف، Query کامل، خروجی مورد انتظار و نکته کاربردی دارد. اشیای آزمایشی را در پایگاه توسعه اجرا کنید و از اجرای کدهای آموزشی روی Production بدون بازبینی مجوز و اثر قفل خودداری نمایید.
مثال 1: درج ساده و دریافت شناسه
مثال پایه با مقدار یا محیط کنترلشده است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #Customer(Id int IDENTITY(1,1), Name nvarchar(40));
INSERT #Customer(Name) VALUES(N'مینا');
SELECT @@IDENTITY AS NewId;
DROP TABLE #Customer;
| خروجی مورد انتظار | تفسیر |
|---|
| 1 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 2: چند درج پیاپی
نمونه قابل اجرا روی داده آزمایشی است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #Item(Id int IDENTITY(10,1), Title nvarchar(20));
INSERT #Item(Title) VALUES(N'A');
INSERT #Item(Title) VALUES(N'B');
SELECT @@IDENTITY AS LastId;
DROP TABLE #Item;
| خروجی مورد انتظار | تفسیر |
|---|
| 11 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 3: درج چندردیفی
کاربرد در SELECT و مشاهده خروجی است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #Batch(Id int IDENTITY(1,1), Code char(1));
INSERT #Batch(Code) VALUES('A'),('B'),('C');
SELECT @@IDENTITY AS LastGeneratedId;
DROP TABLE #Batch;
| خروجی مورد انتظار | تفسیر |
|---|
| 3 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 4: تبدیل نوع خروجی
کاربرد در تصمیمگیری یا کنترل جریان است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #Invoice(Id bigint IDENTITY(1000,1), Amount money);
INSERT #Invoice(Amount) VALUES(125000);
SELECT CONVERT(bigint, @@IDENTITY) AS InvoiceId;
DROP TABLE #Invoice;
| خروجی مورد انتظار | تفسیر |
|---|
| 1000 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 5: بررسی مقدار بدون درج
ترکیب با قابلیتهای دیگر SQL Server است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
-- در اتصال تازه ممکن است مقدار NULL باشد
SELECT @@IDENTITY AS SessionIdentity;
| خروجی مورد انتظار | تفسیر |
|---|
| NULL یا آخرین مقدار نشست | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 6: مقایسه با SCOPE IDENTITY
بررسی مقدار تهی یا وضعیت بدون داده است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #ScopeDemo(Id int IDENTITY, Value int);
INSERT #ScopeDemo(Value) VALUES(7);
SELECT @@IDENTITY AS SessionId, SCOPE_IDENTITY() AS ScopeId;
DROP TABLE #ScopeDemo;
| خروجی مورد انتظار | تفسیر |
|---|
| هر دو برابر 1 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 7: استفاده همراه خروجی INSERT
رفتار مرزی و شرایط غیرمعمول است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #OutputDemo(Id int IDENTITY, Name nvarchar(20));
INSERT #OutputDemo(Name) OUTPUT inserted.Id VALUES(N'کالا');
SELECT @@IDENTITY AS SessionLastId;
DROP TABLE #OutputDemo;
| خروجی مورد انتظار | تفسیر |
|---|
| شناسه درجشده | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 8: ثبت شناسه در متغیر
سناریوی واقعی پایش یا گزارشگیری سازمانی است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #Ticket(Id int IDENTITY(500,5), Subject nvarchar(30));
INSERT #Ticket(Subject) VALUES(N'پشتیبانی');
DECLARE @TicketId numeric(38,0) = @@IDENTITY;
SELECT @TicketId AS TicketId;
DROP TABLE #Ticket;
| خروجی مورد انتظار | تفسیر |
|---|
| 500 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 9: روش نامطمئن و اصلاح آن
روش اشتباه و نسخه اصلاحشده است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #SafeId(Id int IDENTITY, Value int);
INSERT #SafeId(Value) VALUES(9);
SELECT CONVERT(int, SCOPE_IDENTITY()) AS RecommendedId,
CONVERT(int, @@IDENTITY) AS SessionId;
DROP TABLE #SafeId;
| خروجی مورد انتظار | تفسیر |
|---|
| در این مثال هر دو 1 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: این نمونه مرز میان روش شکننده و الگوی قابل اتکا را نشان میدهد. Trigger میتواند مقدار آن را تغییر دهد؛ برای دریافت شناسه همان Scope معمولاً SCOPE_IDENTITY انتخاب امنتری است. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
مثال 10: درج گروهی با OUTPUT
نکته کارایی، ایمنی یا نگهداشتپذیری است. هدف این است که رفتار @@IDENTITY در یک Batch روشن دیده شود و نتیجه به حدس یا وضعیت اتصال دیگری وابسته نباشد. کد را ابتدا در محیط آزمایشی اجرا کنید و در پروژه واقعی نام اشیا و مجوزها را با استاندارد سازمان هماهنگ سازید.
CREATE TABLE #BulkId(Id int IDENTITY, Code varchar(10));
DECLARE @Ids TABLE(Id int);
INSERT #BulkId(Code) OUTPUT inserted.Id INTO @Ids VALUES('X'),('Y');
SELECT Id FROM @Ids ORDER BY Id;
DROP TABLE #BulkId;
| خروجی مورد انتظار | تفسیر |
|---|
| 1 و 2 | نتیجه، رفتار @@IDENTITY را در همین سناریو نشان میدهد. |
نکته کاربردی: پس از اجرای دستور، خروجی را در همان Scope و نشست تفسیر کنید. خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. در سامانه پرترافیک، ثبت زمان، نام پایگاه داده و شناسه نشست کنار نتیجه میتواند عیبیابی را سریعتر کند.
سؤالات متداول
پرسش 1: @@IDENTITY دقیقاً چه کاری انجام میدهد؟
@@IDENTITY آخرین مقدار Identity تولیدشده در کل نشست جاری را بدون محدودیت Scope برمیگرداند. خروجی باید در متن همان Batch و با توجه به Scope، Session و دستور قبلی تفسیر شود؛ جدا کردن آن از زمینه اجرا میتواند نتیجهای ظاهراً درست اما از نظر تجاری اشتباه بسازد.
پرسش 2: بهترین زمان خواندن @@IDENTITY چه موقع است؟
بهترین زمان بلافاصله پس از دستور مرتبط است. اگر مقدار برای چند مرحله بعد لازم است، آن را در متغیری با نوع مناسب ذخیره کنید و همراه شناسه عملیات ثبت نمایید تا دستورهای واسط مقدار یا معنای آن را تغییر ندهند.
پرسش 3: آیا @@IDENTITY برای سامانههای سازمانی مناسب است؟
بله، مشروط بر اینکه قرارداد استفاده، مدیریت خطا و تست همزمانی مشخص باشد. در طراحی حرفهای، این تابع بخشی از راهحل است و در کنار Transaction، Logging، مجوز حداقلی و پایش Query به کار میرود.
پرسش 4: برای پیادهسازی صحیح آن به مشاوره SQL Server نیاز است؟
در کد ساده خیر، اما در سامانههای مالی، انبار، احراز هویت یا پردازش گروهی بررسی Triggerها، Scopeها و الگوی تراکنش اهمیت زیادی دارد. بازبینی تخصصی میتواند از خطاهای خاموش و هزینه اصلاح داده جلوگیری کند.
پرسش 5: تفاوت @@IDENTITY با گزینههای نزدیک چیست؟
تفاوت اصلی در دامنه مشاهده و نوع اطلاعات است. باید مشخص شود نیاز شما مربوط به آخرین Statement، نشست جاری، Scope جاری، جدول مشخص یا Metadata سرور است؛ سپس تابعی انتخاب شود که دقیقاً همان مرز را پوشش دهد.
پرسش 6: آیا میتوان این الگو را در Stored Procedure پروژه پیاده کرد؟
بله. بهتر است مقدار در همان Procedure گرفته شود، نوع خروجی صریح باشد، خطا با TRY...CATCH مدیریت شود و نتیجه از طریق Result Set، پارامتر OUTPUT یا قرارداد سرویس بازگردد. تست یکپارچه نیز حالت موفق و شکست را پوشش دهد.
پرسش 7: خطای رایج هنگام استفاده از @@IDENTITY چیست؟
فرض برابری همیشگی با SCOPE_IDENTITY یکی از خطاهای متداول است. خطای دیگر، اتکا به نتیجه بدون ثبت Context اجراست. نسخه اصلاحشده باید زمان خواندن، Scope، رفتار تراکنش و نوع تبدیل را آشکار کند.
پرسش 8: اثر @@IDENTITY بر Performance چیست؟
خواندن آن سبک است، اما اتکا به مقدار مبهم در زنجیره Triggerها میتواند خطاهای دادهای پرهزینه ایجاد کند. هزینه اصلی معمولاً از Query یا Transaction پیرامون آن میآید، نه خود تابع. اندازهگیری با Actual Execution Plan، Query Store و Extended Events باید روی کل جریان انجام شود.
پرسش 9: Best Practice اصلی برای @@IDENTITY چیست؟
مقدار را نزدیک به دستور مرجع بخوانید، در نوع مناسب ذخیره کنید، نتیجههای مرزی مانند صفر یا NULL را تست کنید و برای عملیات حساس گزارش ممیزی بسازید. از تکیه بر ترتیب اتفاقی دستورات یا رشتههای Hard-coded دوری کنید.
پرسش 10: این قابلیت در کدام نسخههای SQL Server کار میکند؟
این قابلیت در نسخههای رایج و پشتیبانیشده SQL Server در دسترس است، اما امکانات مکمل مانند SESSION_CONTEXT، THROW یا برخی DMVها به نسخه و سطح سازگاری وابستهاند. پیش از استقرار، مستندات همان نسخه و Compatibility Level پایگاه داده را کنترل کنید.
سؤالات مصاحبه SQL Server
سؤال 1: مرز مشاهده @@IDENTITY چیست؟
پاسخ حرفهای باید مشخص کند تابع به Statement، Scope، Session، Table یا Server مربوط است و یک مثال نقض نیز ارائه دهد. گفتن نام تابع بدون توضیح مرز مشاهده برای مصاحبه فنی کافی نیست.
سؤال 2: چگونه مقدار را بدون Race Condition مصرف میکنید؟
مقدار باید نزدیک به عملیات مرجع، در همان اتصال و داخل قرارداد تراکنش خوانده شود. برای چند ردیف یا خروجیهای حساس، قابلیت OUTPUT یا Metadata ساختیافته میتواند انتخاب دقیقتری باشد.
سؤال 3: در CATCH چه اطلاعاتی ثبت میکنید؟
شماره و متن خطا، Procedure، Line، XACT_STATE، @@TRANCOUNT، نام پایگاه داده، SPID و شناسه همبستگی از اطلاعات مفید هستند. داده حساس نباید بدون پالایش وارد Log شود.
سؤال 4: چطور این کد را تست میکنید؟
تست موفق، نتیجه خالی، خطا، تراکنش باز، اجرای همزمان و وجود Trigger یا دستور واسط باید جداگانه پوشش داده شود. تست باید مقدار خروجی و وضعیت نهایی داده را هر دو بررسی کند.
سؤال 5: چه زمانی گزینه دیگری را انتخاب میکنید؟
وقتی تابع مرز موردنیاز را پوشش نمیدهد یا فقط یک مقدار از مجموعهای بزرگ را برمیگرداند. انتخاب باید بر اساس هدف تجاری، همزمانی، نسخه SQL Server و قابلیت مشاهدهپذیری انجام شود.