مقایسه عملگرهای NOT EQUAL در شرط WHERE SQL Server: کدام گزینه بهینهتر است؟
دستور WHERE
در SQL برای فیلتر کردن رکوردها در یک جدول استفاده میشود تا فقط سطرهایی که یک شرط مشخص را برآورده میکنند، در نتایج گنجانده شوند. این دستور با عبارتهای SELECT
، UPDATE
و DELETE
کاربرد دارد. این مقاله بر روی چگونگی استفاده از عملگر NOT EQUAL
در شرط WHERE
در SQL Server تمرکز دارد.
SQL Server چندین عملگر NOT EQUAL
را برای مقایسه ارائه میدهد. این عملگر برای بررسی اینکه آیا یک عبارت با عبارت دیگری برابر نیست، به کار میرود. در ادامه به بررسی عملگرهای زیر خواهیم پرداخت:
<> (Less than or Greater than)
!= (Exclamation mark followed by Equal sign)
NOT EXISTS
NOT IN
اجازه دهید یک پایگاه داده و جدول نمونه ایجاد کنیم تا کاربرد عملگر NOT EQUAL
در شرط WHERE
در SQL را نمایش دهیم.
USE [master]
GO
IF EXISTS (SELECT * FROM sys.databases WHERE name = 'NOT_EQUAL_DB')
BEGIN
ALTER DATABASE [NOT_EQUAL_DB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE [NOT_EQUAL_DB]
END
GO
CREATE DATABASE [NOT_EQUAL_DB]
GO
USE [NOT_EQUAL_DB]
GO
CREATE TABLE [dbo].[Employee]
(
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[EmployeeName] [varchar](50) NULL,
[Department] [varchar](50) NULL,
[Salary] [decimal](18, 2) NULL,
[City] [varchar](50) NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED ([EmployeeId] ASC)
)
GO
INSERT INTO [dbo].[Employee] ([EmployeeName], [Department], [Salary], [City]) VALUES
('John Smith', 'IT', 60000.00, 'New York'),
('Jane Doe', 'HR', 55000.00, 'London'),
('Peter Jones', 'IT', 62000.00, 'New York'),
('Mary White', 'Finance', 70000.00, 'Paris'),
('David Green', 'HR', 58000.00, 'London'),
('Emily Black', 'IT', 61000.00, 'New York'),
('Chris Brown', 'Finance', 68000.00, 'Paris'),
('Sarah Davis', 'HR', 56000.00, 'London'),
('Michael Johnson', 'IT', 63000.00, 'New York'),
('Laura Wilson', 'Marketing', 59000.00, 'Berlin'),
('Robert Taylor', 'Marketing', 60000.00, 'Berlin'),
('Patricia Moore', 'IT', 65000.00, 'New York')
GO
عملگر <>
یک عملگر استاندارد SQL برای «برابر نبودن» است و در سیستمهای پایگاه داده مختلف پشتیبانی میشود. این عملگر برای فیلتر کردن رکوردهایی که مقداری خاص را ندارند، استفاده میشود:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] <> 'IT'
خروجی این کوئری تمام رکوردهای کارمندانی را نشان میدهد که بخش (Department) آنها «IT» نیست. این نتایج شامل کارمندانی از بخشهای HR، Finance و Marketing است.
عملگر !=
نیز یک عملگر «برابر نبودن» است، اما بخشی از استاندارد ANSI SQL نیست. این عملگر به طور خاص در SQL Server و برخی دیگر از سیستمهای پایگاه داده مانند MySQL و PostgreSQL پشتیبانی میشود، اما در Oracle خیر. عملکرد آن در SQL Server مشابه <>
است:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] != 'IT'
خروجی این کوئری که از عملگر !=
استفاده میکند، مشابه عملگر <>
است و نتایج یکسانی را برمیگرداند.
عملگرهای <>
و !=
در SQL Server رفتار یکسانی دارند. انتخاب بین آنها اغلب به ترجیح شخصی یا استانداردهای کدنویسی درون یک سازمان بستگی دارد. با این حال، برای حداکثر سازگاری در سیستمهای پایگاه داده مختلف، عموماً توصیه میشود از عملگر <>
استفاده شود، زیرا بخشی از استاندارد ANSI SQL است.
یک نکته مهم در مورد نحوه برخورد این عملگرها با مقادیر NULL
است. در SQL، مقدار NULL
با هیچ چیز برابر نیست، حتی با خودش. بنابراین، اگر سعی کنید یک ستون با مقدار NULL
را با استفاده از <>
یا !=
مقایسه کنید، آن سطر در نتایج گنجانده نخواهد شد. برای مثال، اگر کارمندانی با بخش NULL
داشته باشیم:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] <> 'IT'
کوئری بالا رکوردهایی را بازمیگرداند که Department آنها «IT» نیست و Department آنها NULL
نیست. اگر میخواهید رکوردهایی را که Department آنها NULL
است نیز شامل شود، باید به صراحت آن را بررسی کنید:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] <> 'IT' OR [Department] IS NULL
عملگر NOT IN
برای تعیین اینکه آیا یک مقدار در لیستی از مقادیر مشخص یا در مجموعه نتایج یک سابکوئری وجود ندارد، استفاده میشود. این عملگر میتواند زمانی مفید باشد که نیاز به حذف چندین مقدار خاص داشته باشید:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] NOT IN ('IT', 'Finance')
مشابه عملگرهای <>
و !=
، عملگر NOT IN
نیز رفتار خاصی با مقادیر NULL
دارد. اگر هر مقداری در لیست (یا نتیجه سابکوئری) عملگر NOT IN
، NULL
باشد، کل شرط NOT IN
برای همه سطرها به UNKNOWN
ارزیابی میشود و بنابراین هیچ سطری برگردانده نخواهد شد. این یک نکته حیاتی و یک دام رایج است:
-- اگر 'NULL' در لیست باشد، نتایج غیرمنتظره خواهد بود (هیچ رکوردی برنمیگردد)
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] NOT IN ('IT', NULL)
برای استفاده صحیح از NOT IN
در صورتی که مقادیر NULL
ممکن است وجود داشته باشند، مطمئن شوید که لیست مقادیر یا نتیجه سابکوئری حاوی NULL
نیست، یا صراحتاً NULL
ها را در منطق کوئری خود مدیریت کنید. به عنوان مثال، فیلتر کردن NULL
ها از سابکوئری:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee]
WHERE
[Department] NOT IN (SELECT [Department] FROM [dbo].[Employee] WHERE [Department] IS NOT NULL)
عملگر NOT EXISTS
برای تعیین اینکه آیا یک سابکوئری هیچ سطری را برنمیگرداند، استفاده میشود. اگر سابکوئری هیچ سطری را برنگرداند، شرط NOT EXISTS
صحیح (TRUE) است. این عملگر به ویژه برای فیلتر کردن رکوردهای جدول اصلی بر اساس عدم وجود رکوردهای مرتبط در جدول دیگر مفید است.
بر خلاف NOT IN
، عملگر NOT EXISTS
در نحوه برخورد با مقادیر NULL
در سابکوئری، کارآمدتر و قابل پیشبینیتر است، زیرا مقادیر NULL
در سابکوئری تاثیری بر نتیجه نهایی NOT EXISTS
نمیگذارند. مثال زیر کارمندانی را انتخاب میکند که در بخش IT نیستند:
SELECT
[EmployeeId],
[EmployeeName],
[Department],
[Salary],
[City]
FROM
[dbo].[Employee] e
WHERE NOT EXISTS (
SELECT 1
FROM [dbo].[Employee]
WHERE [Department] = 'IT' AND [EmployeeId] = e.[EmployeeId]
)
خروجی این کوئری نیز مشابه مثالهای قبلی است که کارمندانی را از بخشهای غیر IT بازمیگرداند.
وقتی صحبت از عملکرد میشود، عملگرهای <>
و !=
عموماً سریعترین گزینهها برای مقایسههای ساده تک مقداری هستند. NOT IN
میتواند برای لیستهای کوتاه مقادیر یا سابکوئریهای کوچک کارآمد باشد، اما باید مراقب رفتار آن با NULL
ها بود. NOT EXISTS
برای سابکوئریها معمولاً عملکرد بهتری نسبت به NOT IN
دارد، به خصوص در مواجهه با NULL
ها یا سابکوئریهای پیچیدهتر، زیرا NOT EXISTS
به محض یافتن اولین تطابق متوقف میشود.
برای بررسی دقیقتر، میتوانیم زمان اجرای کوئریها و طرحهای اجرایی (Execution Plans) آنها را مقایسه کنیم. به عنوان مثال، میتوانید از دستورات SET STATISTICS IO ON
و SET STATISTICS TIME ON
برای مشاهده جزئیات منابع مصرفی هر کوئری استفاده کنید. اما در بیشتر سناریوهای معمول و برای مقایسههای ساده NOT EQUAL
، عملگرهای <>
و !=
به دلیل سادگی و کارایی استانداردشان، انتخابهای مناسبی هستند.