بازیابی دادههای منحصر به فرد در SQL Server: راهنمای جامع SELECT DISTINCT
دستور `SELECT DISTINCT` در SQL Server برای بازیابی ردیفهای منحصر به فرد از یک جدول استفاده میشود. این دستور به شما امکان میدهد تا ردیفهای تکراری را از مجموعه نتایج حذف کنید و فقط مقادیر متمایز را نمایش دهید. در واقع، `DISTINCT` تمام مقادیر تکراری را در ستون یا ستونهایی که مشخص کردهاید، حذف میکند و تنها یک نسخه از هر مقدار منحصر به فرد را بازمیگرداند. این کار میتواند برای تحلیل دادهها، گزارشگیری یا تضمین صحت دادهها بسیار مفید باشد.
#### بازیابی دادههای منحصر به فرد با SELECT DISTINCT
برای درک بهتر عملکرد `SELECT DISTINCT`، فرض کنید جدولی به نام `Employees` داریم که شامل اطلاعات کارمندان است. این جدول ممکن است شامل ستونهایی مانند `EmployeeId`، `FirstName`، `LastName` و `Department` باشد.
برای ایجاد این جدول و درج دادههای نمونه، میتوانید از دستورات زیر استفاده کنید:
USE tempdb;
GO
IF OBJECT_ID('tempdb.dbo.Employees') IS NOT NULL
DROP TABLE tempdb.dbo.Employees;
GO
CREATE TABLE Employees
(
EmployeeId INT IDENTITY(1,1),
FirstName VARCHAR(100),
LastName VARCHAR(100),
Department VARCHAR(100)
);
GO
INSERT INTO Employees (FirstName, LastName, Department) VALUES
('John', 'Doe', 'Sales'),
('Jane', 'Smith', 'Marketing'),
('John', 'Doe', 'Sales'),
('Emily', 'Jones', 'HR'),
('Mike', 'Brown', 'IT'),
('Jane', 'Smith', 'Marketing'),
('Sarah', 'Davis', 'Finance'),
('David', 'Wilson', 'IT'),
('Emily', 'Jones', 'HR'),
('Chris', 'Miller', 'Sales');
GO
حال، برای مشاهده تمام ردیفهای موجود در جدول `Employees`، میتوانید از دستور `SELECT *` استفاده کنید:
SELECT *
FROM Employees;
خروجی این کوئری شامل تمام ردیفها، از جمله ردیفهای تکراری، خواهد بود.
#### استفاده از SELECT DISTINCT با یک ستون
اگر میخواهید لیست منحصر به فرد دپارتمانها را از جدول `Employees` بازیابی کنید، میتوانید از `SELECT DISTINCT` با ستون `Department` استفاده کنید. این کوئری تنها نام دپارتمانهای متمایز را نمایش میدهد، حتی اگر چندین کارمند در یک دپارتمان باشند.
SELECT DISTINCT Department
FROM Employees;
این دستور به شما کمک میکند تا به سرعت متوجه شوید چه دپارتمانهایی در شرکت وجود دارند، بدون اینکه نام هر دپارتمان تکرار شود.
#### استفاده از SELECT DISTINCT با چندین ستون
شما میتوانید `SELECT DISTINCT` را با چندین ستون استفاده کنید. در این حالت، `DISTINCT` ترکیبی منحصر به فرد از مقادیر تمام ستونهای مشخص شده را بازمیگرداند. به عبارت دیگر، یک ردیف تنها در صورتی تکراری در نظر گرفته میشود که مقادیر تمام ستونهای انتخاب شده در آن ردیف با ردیف دیگری یکسان باشد.
برای بازیابی ترکیبات منحصر به فرد نام، نام خانوادگی و دپارتمان:
SELECT DISTINCT FirstName, LastName, Department
FROM Employees;
در این مثال، اگر “John Doe” دو بار در دپارتمان “Sales” حضور داشته باشد، تنها یک بار نمایش داده میشود. اما اگر “John Doe” یک بار در “Sales” و یک بار در “Marketing” باشد، هر دو ترکیب منحصر به فرد در خروجی ظاهر خواهند شد.
#### استفاده از SELECT DISTINCT همراه با ORDER BY
شما میتوانید نتایج `DISTINCT` را با استفاده از دستور `ORDER BY` مرتب کنید. این کار به شما امکان میدهد تا دادههای منحصر به فرد را به ترتیبی خاص، مثلاً الفبایی، مشاهده کنید.
برای بازیابی دپارتمانهای منحصر به فرد و مرتبسازی آنها بر اساس نام دپارتمان:
SELECT DISTINCT Department
FROM Employees
ORDER BY Department ASC;
این کوئری لیست دپارتمانهای منحصر به فرد را به ترتیب صعودی نام دپارتمانها نمایش میدهد.
#### استفاده از SELECT DISTINCT همراه با COUNT()
تابع تجمعی `COUNT()` به همراه `DISTINCT` برای شمارش تعداد مقادیر منحصر به فرد در یک ستون استفاده میشود. این ترکیب برای پاسخ به سوالاتی مانند “چند دپارتمان مختلف داریم؟” بسیار مفید است.
برای شمارش تعداد دپارتمانهای منحصر به فرد:
SELECT COUNT(DISTINCT Department) AS NumberOfUniqueDepartments
FROM Employees;
نتیجه این کوئری یک عدد است که تعداد دپارتمانهای متمایز را در جدول نشان میدهد.
#### استفاده از SELECT DISTINCT همراه با AVG() و SUM()
توابع تجمعی `AVG()` (میانگین) و `SUM()` (جمع) نیز میتوانند با `DISTINCT` ترکیب شوند تا عملیات را تنها بر روی مقادیر منحصر به فرد انجام دهند. به عنوان مثال، اگر ستونی مانند `Salary` (حقوق) داشته باشید و بخواهید میانگین حقوقهای منحصر به فرد را محاسبه کنید.
برای درک این موضوع، فرض کنید ستون `Salary` را به جدول `Employees` اضافه کردهایم:
ALTER TABLE Employees
ADD Salary DECIMAL(10, 2);
GO
UPDATE Employees SET Salary = 50000.00 WHERE FirstName = 'John' AND LastName = 'Doe';
UPDATE Employees SET Salary = 60000.00 WHERE FirstName = 'Jane' AND LastName = 'Smith';
UPDATE Employees SET Salary = 50000.00 WHERE FirstName = 'Emily' AND LastName = 'Jones';
UPDATE Employees SET Salary = 70000.00 WHERE FirstName = 'Mike' AND LastName = 'Brown';
UPDATE Employees SET Salary = 65000.00 WHERE FirstName = 'Sarah' AND LastName = 'Davis';
UPDATE Employees SET Salary = 70000.00 WHERE FirstName = 'David' AND LastName = 'Wilson';
UPDATE Employees SET Salary = 50000.00 WHERE FirstName = 'Chris' AND LastName = 'Miller';
حال، برای محاسبه میانگین حقوقهای منحصر به فرد و جمع حقوقهای منحصر به فرد:
SELECT
AVG(DISTINCT Salary) AS AverageUniqueSalary,
SUM(DISTINCT Salary) AS SumUniqueSalary
FROM Employees;
این کوئری ابتدا مقادیر حقوق منحصر به فرد را شناسایی کرده و سپس میانگین و جمع آنها را محاسبه میکند.
#### استفاده از SELECT DISTINCT همراه با TOP
`TOP` برای محدود کردن تعداد ردیفهای بازگردانده شده استفاده میشود. ترکیب `TOP` با `DISTINCT` میتواند برای بازیابی N ردیف منحصر به فرد اول بر اساس یک معیار خاص مفید باشد. این معمولاً به همراه `ORDER BY` استفاده میشود تا نتایج قابل پیشبینی باشند.
برای بازیابی ۳ دپارتمان منحصر به فرد اول بر اساس ترتیب الفبایی:
SELECT TOP 3 DISTINCT Department
FROM Employees
ORDER BY Department ASC;
این کوئری سه دپارتمان اول را از لیست دپارتمانهای منحصر به فرد مرتب شده برمیگرداند.
#### استفاده از SELECT DISTINCT همراه با JOIN
`SELECT DISTINCT` میتواند در کوئریهایی که از `JOIN` برای ترکیب دادهها از چندین جدول استفاده میکنند، به کار رود. این کار برای اطمینان از اینکه ردیفهای تکراری ناشی از عملیات `JOIN` حذف میشوند، مفید است.
فرض کنید جدول دیگری به نام `Projects` داریم که دپارتمانها و پروژههای مرتبط را نشان میدهد.
برای ایجاد این جدول:
IF OBJECT_ID('tempdb.dbo.Projects') IS NOT NULL
DROP TABLE tempdb.dbo.Projects;
GO
CREATE TABLE Projects
(
ProjectId INT IDENTITY(1,1),
ProjectName VARCHAR(100),
Department VARCHAR(100)
);
GO
INSERT INTO Projects (ProjectName, Department) VALUES
('Website Redesign', 'Marketing'),
('CRM Implementation', 'Sales'),
('Database Upgrade', 'IT'),
('Financial Audit', 'Finance'),
('Employee Training', 'HR'),
('New Product Launch', 'Marketing'),
('Sales Growth Plan', 'Sales');
GO
اگر بخواهیم نام دپارتمانهای منحصر به فردی را که هم کارمند دارند و هم پروژه فعال، بازیابی کنیم:
SELECT DISTINCT E.Department
FROM Employees AS E
JOIN Projects AS P ON E.Department = P.Department;
این کوئری لیستی از دپارتمانهایی را که در هر دو جدول `Employees` و `Projects` وجود دارند و در هر دو دارای رکورد هستند، به صورت منحصر به فرد نمایش میدهد.
#### ملاحظات عملکردی SELECT DISTINCT
استفاده از `SELECT DISTINCT` میتواند بر عملکرد کوئریها تأثیر بگذارد، به خصوص در جداول بزرگ. هنگامی که `DISTINCT` استفاده میشود، SQL Server نیاز دارد تا تمام ردیفها را پردازش کند، آنها را مرتب کند و سپس ردیفهای تکراری را حذف کند. این عملیات میتواند مصرف منابع (CPU و I/O) را افزایش دهد.
برای بهبود عملکرد، میتوانید اقدامات زیر را در نظر بگیرید:
* **ایندکسگذاری (Indexing):** ایندکسها بر روی ستونهایی که در `SELECT DISTINCT` استفاده میشوند، میتوانند به SQL Server در یافتن و پردازش سریعتر مقادیر منحصر به فرد کمک کنند.
* **انتخاب ستونهای کمتر:** هرچه تعداد ستونهای بیشتری را با `DISTINCT` انتخاب کنید، کار پردازش برای SQL Server پیچیدهتر میشود. سعی کنید فقط ستونهای ضروری را انتخاب کنید.
* **استفاده از روشهای جایگزین:** در برخی موارد، ممکن است بتوانید با استفاده از `GROUP BY` به نتایج مشابهی دست پیدا کنید که ممکن است در سناریوهای خاص عملکرد بهتری داشته باشد. `GROUP BY` نیز ردیفها را بر اساس ستونهای مشخص شده گروهبندی میکند و یک ردیف برای هر گروه منحصر به فرد بازمیگرداند.
مثالی از استفاده از `GROUP BY` برای دریافت دپارتمانهای منحصر به فرد:
SELECT Department
FROM Employees
GROUP BY Department;
این کوئری همان خروجی `SELECT DISTINCT Department` را تولید میکند و در برخی موارد ممکن است عملکرد بهتری داشته باشد، به خصوص زمانی که نیاز به توابع تجمعی دیگر نیز دارید.