#آموزش: خطر استفاده از عملگر Not IN ❗️
در این آموزش علاوه بر آشنایی با نحوه عملکرد عملگر Not IN ، با نکاتی پیرامون مقدار null در sqlserver هم آشنایی پیدا خواهید کرد.
خیلی از مواقع ممکن هست برای تهیه گزارشاتی مانند لیست کارمندانی که حقوق فلان ماه رو دریافت نکرده اند، لیست کالاهایی که رزرو سفارش نشده اند و ... از عملگر Not IN به صورت زیر استفاده کنیم :
select * from first_table as a جدول حاوی کلیه رکوردها
where
a.id Not IN(Select id from second_table where ....)
به عنوان یک اشاره مختصر : همونطور که میدونید عملگرهایی مانند Exists - IN - Not IN - Not Exists جهت انجام عملیات از Join (semi join - inner join) استفاده می کنند .
در هر حال، جهت تولید خروجی نهایی، باید یک مقایسه بین id رکوزردهای جدول اول (first table) و جدول دوم (second table) که دارای شرط خاصی هستند انجام بشود. نکته مهم این هست که در عملگر not in این مقایسه به دنباله ای از ANd ها تبدیل می شود ( بر خلاف عملگر IN که به دنباله ای از OR ها تبدیل می شود).
و اما مشکل زمانی ایجاد می شود که در مقایسه ما یک مقدار با null ست شده باشد. به مثال زیر دقت کنید:
SELECT *
FROM dbo.Person
WHERE ID NOT IN (1,2,null)
با بررسی Execution plan خواهید دید که مقایسه به این صورت خواهد بود :
[dbo].[Person].[ID]< > 1) AND
[dbo].[Person].[ID]< >2) AND
[dbo].[Person].[ID]< >null)
به اینصورت خروجی شما همیشه تهی خواهد بود و هیچ رکوردی رو در خروجی نخواهید دید !!!!!
و اما دلیل بروز این مشکل:
دقت کنید برای نمایش یک رکورد، بایستی حاصل مقایسه (عبارت داخل پرانتز) برابر با true شود.
نکته مهم در اینجا وجود مقدار null هست و دو نکته مهم در رابطه با null:
1- نتیجه انجام هر مقایسه یا عملیاتی با null برابر است با null (این مورد رو با نوشتن کوئری های ساده مانند : select null*2 بررسی کنیذ.
2- نتیجه مقایسه منطقی AND هر مقداری با null برابر است با false
با توجه به دو نکته بالا، فرض کنید از جدول اول داریم: id=2
پس در ابتدا حاصل مقایسه ها:
1< >1 —-------------->false
1< >2) —--------------->true
1< > null) —------------->null با توجه به نکته 1
در مرحله دوم انجام AND بین نتایج:
flase AND true AND null —----------------------->false با توجه به نکته 2
راه حل:
1- با استفاده از عملگر Not Exists این مشکل را نخواهید داشت.
2- در صورت ایجاد رابطه (Relationship) بین جداول، جدول Child نمی تواند مقداری که در جدول Parent وجود ندارد را داشته باشد و از آنجایی که فیلذ جدول Parent هم Unique می باشد پس مشکل فوق در استفاده از عملگر Not in پیش نخواهد آمد .
محسن بندامیر
@Mohsen_Bandamir