SELECT INTO در SQL Server: ایجاد جداول جدید به روشی کارآمد
دستور SQL SELECT INTO برای ایجاد یک جدول جدید و درج دادهها در آن از یک جدول موجود استفاده میشود. در ادامه، نمونههای مختلفی از نحوه استفاده از این دستور را در SQL Server بررسی خواهیم کرد.
SELECT INTO در مقابل CREATE TABLE AS SELECT در SQL Server
هر دو دستور SQL SELECT INTO و CREATE TABLE AS SELECT برای ایجاد یک جدول جدید و پر کردن آن با دادهها از یک جدول یا کوئری دیگر استفاده میشوند. با این حال، تفاوتهایی بین این دو وجود دارد.
SELECT INTO یک دستور SQL استاندارد است که توسط اکثر سیستمهای مدیریت پایگاه داده رابطهای (RDBMS) پشتیبانی میشود. این دستور برای ایجاد یک جدول جدید و درج دادهها در آن در یک مرحله استفاده میشود.
CREATE TABLE AS SELECT یک دستور SQL غیر استاندارد است که مختص برخی RDBMSها مانند PostgreSQL و Oracle است. این دستور نیز برای ایجاد یک جدول جدید و درج دادهها در آن استفاده میشود، اما نیاز دارد که ابتدا جدول ایجاد شده و سپس دادهها در آن درج شوند.
در اینجا برخی تفاوتهای کلیدی آورده شده است:
-
SELECT INTO یک جدول جدید با همان ساختار و انواع داده (Data Types) جدول منبع ایجاد میکند. CREATE TABLE AS SELECT به شما امکان میدهد انواع داده ستونها را در جدول جدید مشخص کنید.
-
SELECT INTO از ایجاد محدودیتها (Constraints)، ایندکسها (Indexes) یا سایر ویژگیهای شیء (Object Properties) در جدول جدید پشتیبانی نمیکند. CREATE TABLE AS SELECT به شما امکان میدهد محدودیتها، ایندکسها و سایر ویژگیهای شیء را در جدول جدید مشخص کنید.
-
SELECT INTO به طور کلی برای ایجاد جداول جدید از تعداد زیادی ردیف سریعتر است، زیرا برای درج انبوه (Bulk Inserts) بهینهسازی شده است. CREATE TABLE AS SELECT میتواند برای جداول بزرگ کندتر باشد، زیرا ابتدا جدول را ایجاد کرده و سپس دادهها را ردیف به ردیف درج میکند.
نمونه پایه SELECT INTO در SQL Server
بیایید با یک مثال ساده از نحوه استفاده از دستور SELECT INTO برای ایجاد یک جدول جدید از یک جدول موجود شروع کنیم. ما یک جدول جدید به نام “EmployeesCopy” را از جدول “Employees” در پایگاه داده “AdventureWorks2019” ایجاد خواهیم کرد.
ابتدا، بیایید مطمئن شویم که جدول موجود است؛ در غیر این صورت، آن را ایجاد میکنیم.
USE AdventureWorks2019;
GO
IF OBJECT_ID('dbo.Employees', 'U') IS NOT NULL
DROP TABLE dbo.Employees;
GO
CREATE TABLE dbo.Employees
(
EmployeeID INT PRIMARY KEY,
FirstName NVARCHAR(50),
LastName NVARCHAR(50),
HireDate DATE,
Salary DECIMAL(10, 2)
);
GO
INSERT INTO dbo.Employees (EmployeeID, FirstName, LastName, HireDate, Salary)
VALUES
(1, 'John', 'Doe', '2020-01-01', 50000.00),
(2, 'Jane', 'Smith', '2020-02-15', 60000.00),
(3, 'Peter', 'Jones', '2020-03-01', 55000.00);
GO
اکنون، بیایید با استفاده از SELECT INTO یک جدول جدید به نام “EmployeesCopy” را از جدول “Employees” ایجاد کنیم. این کار یک جدول جدید با همان ساختار و دادههای جدول “Employees” ایجاد خواهد کرد.
SELECT
EmployeeID,
FirstName,
LastName,
HireDate,
Salary
INTO
EmployeesCopy
FROM
Employees;
GO
پس از اجرای دستور فوق، یک جدول جدید به نام “EmployeesCopy” در پایگاه داده “AdventureWorks2019” ایجاد میشود و حاوی تمام دادههای جدول “Employees” خواهد بود.
مشخص کردن ستونها در SELECT INTO
شما همچنین میتوانید با لیست کردن صریح ستونها در دستور SELECT، مشخص کنید که کدام ستونها در جدول جدید گنجانده شوند. این کار به شما امکان میدهد یک جدول جدید با زیرمجموعهای از ستونهای جدول منبع ایجاد کنید.
به عنوان مثال، بیایید یک جدول جدید به نام “EmployeeNames” ایجاد کنیم که فقط شامل ستونهای “FirstName” و “LastName” از جدول “Employees” باشد.
SELECT
FirstName,
LastName
INTO
EmployeeNames
FROM
Employees;
GO
این دستور یک جدول جدید به نام “EmployeeNames” را تنها با ستونهای “FirstName” و “LastName” ایجاد میکند که با دادههای مربوطه از جدول “Employees” پر شده است.
استفاده از SELECT INTO با JOIN
دستور SELECT INTO را میتوان با بندهای JOIN نیز برای ترکیب دادهها از چندین جدول و ایجاد یک جدول جدید استفاده کرد. این کار زمانی مفید است که شما نیاز به ایجاد یک جدول جدید دارید که شامل دادههای تجمیع شده یا ترکیبی از چندین جدول مرتبط باشد.
به عنوان مثال، فرض کنید یک جدول دیگر به نام “Departments” داریم و میخواهیم یک جدول جدید به نام “EmployeeDepartments” ایجاد کنیم که شامل اطلاعات کارمندان به همراه نام بخشهای آنها باشد.
ابتدا، بیایید جدول Departments را ایجاد کنیم.
IF OBJECT_ID('dbo.Departments', 'U') IS NOT NULL
DROP TABLE dbo.Departments;
GO
CREATE TABLE dbo.Departments
(
DepartmentID INT PRIMARY KEY,
DepartmentName NVARCHAR(50)
);
GO
INSERT INTO dbo.Departments (DepartmentID, DepartmentName)
VALUES
(101, 'Sales'),
(102, 'Marketing'),
(103, 'HR');
GO
اکنون، بیایید جدول “EmployeeDepartments” را با استفاده از SELECT INTO و یک JOIN ایجاد کنیم.
-- Adding a DepartmentID to Employees table for the join
ALTER TABLE dbo.Employees
ADD DepartmentID INT;
GO
UPDATE dbo.Employees
SET DepartmentID = CASE EmployeeID
WHEN 1
THEN 101
WHEN 2
THEN 102
WHEN 3
THEN 101
END;
GO
SELECT
E.EmployeeID,
E.FirstName,
E.LastName,
D.DepartmentName
INTO
EmployeeDepartments
FROM
Employees AS E
JOIN
Departments AS D
ON E.DepartmentID = D.DepartmentID;
GO
این دستور یک جدول جدید به نام “EmployeeDepartments” را ایجاد میکند که حاوی دادههای ترکیب شده از هر دو جدول است.
SELECT INTO و ویژگی Identity (شناسایی)
هنگامی که از SELECT INTO استفاده میکنید، ویژگی Identity یک ستون از جدول منبع به طور پیشفرض به جدول جدید منتقل نمیشود. اگر به ویژگی Identity در جدول جدید نیاز دارید، باید آن را صریحاً تعریف کنید یا از یک راهکار جایگزین استفاده نمایید.
به عنوان مثال، بیایید ببینیم ستون identity چگونه رفتار میکند.
ابتدا، بیایید یک جدول با ستون identity ایجاد کنیم.
IF OBJECT_ID('dbo.Products', 'U') IS NOT NULL
DROP TABLE dbo.Products;
GO
CREATE TABLE dbo.Products
(
ProductID INT IDENTITY(1, 1) PRIMARY KEY,
ProductName NVARCHAR(100),
Price DECIMAL(10, 2)
);
GO
INSERT INTO dbo.Products (ProductName, Price)
VALUES
('Laptop', 1200.00),
('Mouse', 25.00),
('Keyboard', 75.00);
GO
اکنون، بیایید با استفاده از SELECT INTO دادهها را به یک جدول جدید کپی کنیم.
SELECT
ProductID,
ProductName,
Price
INTO
ProductsCopy
FROM
Products;
GO
اگر شمای (Schema) جدول “ProductsCopy” را بررسی کنید، متوجه میشوید که “ProductID” یک ستون INT است اما بدون ویژگی IDENTITY. در صورت نیاز، باید آن را صریحاً اضافه کنید.
SELECT
OBJECT_NAME(object_id) AS TableName,
name AS ColumnName,
is_identity
FROM
sys.columns
WHERE
OBJECT_NAME(object_id) IN ('Products', 'ProductsCopy')
AND name = 'ProductID';
GO
SELECT INTO و محدودیتها/ایندکسها (Constraints/Indexes)
مشابه ویژگی Identity، دستور SELECT INTO محدودیتها (مانند PRIMARY KEY، FOREIGN KEY، UNIQUE، CHECK، DEFAULT) یا ایندکسها را از جدول منبع به جدول جدید منتقل نمیکند. جدول جدید تنها نام ستونها و انواع داده (Data Types) را به ارث میبرد. اگر به این اشیاء نیاز دارید، باید آنها را پس از ایجاد جدول جدید به صورت دستی ایجاد کنید.
SELECT INTO و انواع داده (Data Types)
SELECT INTO انواع داده ستونهای جدول جدید را از ستونهای جدول منبع استنتاج (Infer) میکند. به عنوان مثال، اگر یک ستون در جدول منبع NVARCHAR(50) باشد، ستون متناظر در جدول جدید نیز NVARCHAR(50) خواهد بود.
با این حال، اگر از عبارات (Expressions) یا توابع (Functions) در دستور SELECT استفاده کنید، انواع داده ممکن است به صورت متفاوتی استنتاج شوند. به عنوان مثال، اگر یک ستون را به نوع داده دیگری تبدیل (Cast) کنید، جدول جدید آن تبدیل را منعکس خواهد کرد.
SELECT
CAST(EmployeeID AS BIGINT) AS EmployeeIDBigInt,
FirstName,
LEN(LastName) AS LastNameLength
INTO
EmployeeDataTypes
FROM
Employees;
GO
در این مثال، “EmployeeIDBigInt” از نوع BIGINT و “LastNameLength” از نوع INT خواهد بود، همانطور که توسط تابع LEN استنتاج میشود.
محدودیتهای SELECT INTO
در حالی که SELECT INTO یک دستور قدرتمند برای ایجاد سریع جدول است، اما دارای برخی محدودیتها است:
-
عدم امکان ایجاد مستقیم جدول در پایگاه دادهای دیگر در همان Instance: نمیتوانید از SELECT INTO برای ایجاد مستقیم یک جدول در پایگاه داده دیگری در همان Instance سرور SQL بدون مشخص کردن مسیر کامل استفاده کنید. به عنوان مثال، SELECT * INTO OtherDB.dbo.NewTable FROM CurrentDB.dbo.OldTable; کار میکند، اما SELECT * INTO OtherDB..NewTable FROM CurrentDB..OldTable; به طور مستقیم نه. شما باید طرحواره (Schema) را صریحاً مشخص کنید.
-
عدم امکان ایجاد مستقیم جدول در یک Instance SQL Server متفاوت: SELECT INTO نمیتواند به طور مستقیم یک جدول را در یک Instance متفاوت SQL Server ایجاد کند. برای چنین سناریوهایی معمولاً از Linked Servers یا SSIS استفاده میشود.
-
عدم تعریف صریح ستونها: نمیتوانید انواع داده صریح ستونها، قابلیت NULL (NULLability) یا محدودیتها (PRIMARY KEY، FOREIGN KEY، UNIQUE، CHECK، DEFAULT) را در طول ایجاد جدول تعریف کنید. این موارد باید پس از ایجاد جدول اضافه شوند.
-
عدم کنترل بر Filegroups: نمیتوانید Filegroup (گروه فایل) را برای جدول جدید مشخص کنید. این جدول در Filegroup پیشفرض پایگاه داده ایجاد خواهد شد.
-
جدول نباید از قبل موجود باشد: جدول هدف مشخص شده در بند INTO نباید از قبل موجود باشد. اگر موجود باشد، دستور منجر به خطا خواهد شد.