گاهی دو جدول رویدادهای متفاوتی را نگه میدارند، اما شکل خروجی مورد نیاز یکسان است. مشتری و تأمینکننده میتوانند یک فهرست تماس بسازند، فروش و برگشت کالا یک جریان فعالیت شوند و جدول جاری و آرشیو یک منبع گزارش تشکیل دهند. UNION این خروجیها را عمودی ترکیب میکند.
در این درس هماهنگی تعداد و ترتیب ستونها، سازگاری نوع داده، alias، مدیریت رکورد تکراری، مرتبسازی نهایی و پارامترها بررسی میشود. همچنین روشن میشود چرا در نبود الزام حذف تکرار، UNION ALL انتخاب مناسبتری است.
UNION با JOIN تفاوت دارد. join با تطبیق رکورد مرتبط ستون اضافه میکند، اما UNION سطرهای چند SELECT را زیر هم میگذارد. اشتباه گرفتن آنها میتواند خروجی عریض بهجای فهرست بلند یا رکورد تکراری ناخواسته ایجاد کند.
جایگاه این درس در مسیر آموزش SQL اکسس
این مبحث پس از تجمیع و زیرکوئری قرار میگیرد، زیرا گزارشها اغلب پیش از محاسبه یا فیلتر پیشرفته به یک جریان استاندارد نیاز دارند. وقتی منابع مختلف یک schema خروجی مشترک بسازند، فرم و گزارش و VBA میتوانند با آنها یکسان رفتار کنند.
ابتدا قرارداد خروجی را تعیین کنید: تعداد ستون، ترتیب، معنا، نوع داده و alias. نام ستونهای SELECT اول بهعنوان نام نهایی استفاده میشود؛ بنابراین aliasهای شاخه نخست باید روشن و پایدار باشند.
پیشنیازها و مدل داده نمونه
در مثالها از جدولهای Customers، Orders، OrderDetails، Products و Categories استفاده میشود. CustomerID کلید اصلی مشتری، OrderID کلید اصلی سفارش و ProductID کلید اصلی محصول است. فیلدهای کلید خارجی باید با کلید اصلی متناظر نوع داده سازگار داشته باشند و در پایگاههای بزرگ برای join و فیلترهای پرتکرار ایندکس شوند.
پیش از اجرای مثالها از فایل اکسس نسخه پشتیبان تهیه کنید و نام جدولها و فیلدها را با پایگاه خود تطبیق دهید. اگر نامی فاصله دارد آن را داخل کروشه قرار دهید. ابتدا یک SELECT ساده با تعداد رکورد محدود بسازید و سپس clauseها، پارامترها یا عبارتهای پیشرفته را مرحلهبهمرحله اضافه کنید.
ساختار اصلی و مدل ذهنی
UNION سطرهای چند SELECT سازگار را زیر هم قرار میدهد. هر شاخه باید تعداد ستون یکسان با ترتیب و نوع سازگار داشته باشد. UNION رکورد تکراری را حذف میکند، اما UNION ALL آن را نگه میدارد و معمولاً سریعتر است. ORDER BY فقط یکبار در انتها میآید.
SELECT CustomerID AS EntityID,
CustomerName AS EntityName,
'Customer' AS EntityType
FROM Customers
UNION ALL
SELECT SupplierID AS EntityID,
SupplierName AS EntityName,
'Supplier' AS EntityType
FROM Suppliers
ORDER BY EntityName;دستور را بر اساس جریان منطقی داده تحلیل کنید: ابتدا سطرهای منبع مشخص میشوند، سپس فیلتر سطح رکورد اجرا میشود، داده در صورت نیاز ترکیب یا گروهبندی میشود، ستونهای خروجی محاسبه میشوند، شرط سطح نتیجه اعمال میشود و در پایان مرتبسازی صورت میگیرد. این مدل نشان میدهد چرا جابهجایی یک شرط میتواند نتیجه را تغییر دهد.
کاربردهای مناسب
- ترکیب رکوردهای جاری و آرشیو
- ساخت فهرست تماس مشترک مشتری و تأمینکننده
- ادغام فروش و برگشت در دفتر علامتدار
- ترکیب تراکنش دستی و واردشده
- ساخت منبع مشترک برای گزارش و export
نمونه کاربردی با قواعد واقعی
مثال پیشرفته یک دفتر فعالیت علامتدار میسازد. فروش با مبلغ مثبت و برگشت با مبلغ منفی نمایش داده میشود. هر دو شاخه ستونهای ActivityID، ActivityDate، PartyID، Amount و ActivityType دارند.
PARAMETERS [pStartDate] DateTime, [pEndDate] DateTime;
SELECT O.OrderID AS ActivityID,
O.OrderDate AS ActivityDate,
O.CustomerID AS PartyID,
O.TotalAmount AS Amount,
'Sale' AS ActivityType
FROM Orders AS O
WHERE O.OrderDate Between [pStartDate] And [pEndDate]
UNION ALL
SELECT R.ReturnID AS ActivityID,
R.ReturnDate AS ActivityDate,
R.CustomerID AS PartyID,
-R.ReturnAmount AS Amount,
'Return' AS ActivityType
FROM Returns AS R
WHERE R.ReturnDate Between [pStartDate] And [pEndDate]
ORDER BY ActivityDate, ActivityID;پارامتر تاریخ در هر دو شاخه استفاده میشود و هر SELECT فیلد تاریخ خودش را محدود میکند. ORDER BY فقط پس از آخرین SELECT میآید. UNION ALL رویدادهای مستقل را حتی با مقادیر نمایشی برابر حفظ میکند.
اجرای کوئری از VBA
برای اتوماسیون قابل نگهداری، SQL را بهصورت یک QueryDef نامدار ذخیره و از DAO اجرا کنید. پارامتر صریح از اتصال متن به رشته SQL بهتر است، زیرا Access نوع داده را پیش از اجرا میشناسد. روال زیر الگوی عمومی را نشان میدهد؛ نام QueryDef و پارامترها را با کوئری ذخیرهشده همین درس هماهنگ کنید.
Option Explicit
Public Sub ExportCombinedActivity()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
On Error GoTo CleanFail
Set db = CurrentDb
Set qdf = db.QueryDefs("qryCombinedSalesAndReturns")
qdf.Parameters("pStartDate") = DateSerial(2026, 1, 1)
qdf.Parameters("pEndDate") = DateSerial(2026, 12, 31)
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
Do While Not rs.EOF
Debug.Print rs!ActivityDate, rs!ActivityType, rs!Amount
rs.MoveNext
Loop
CleanExit:
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
Exit Sub
CleanFail:
Debug.Print Err.Number, Err.Description
Resume CleanExit
End Subدر این نمونه Recordset از نوع snapshot برای خواندن نتیجه باز میشود. برای INSERT، UPDATE یا DELETE باید از روش اجرای action query استفاده و RecordsAffected را کنترل کنید. بخش پاکسازی نیز باید اشیا را در حالت موفق و خطا ببندد تا اتصال یا Recordset باز باقی نماند.
روش کنترل نتیجه
- کوئری منبع را بدون clause پیشرفته اجرا و تعداد سطرهای اولیه را ثبت کنید.
- یک حالت کوچک را دستی محاسبه و با خروجی SQL مقایسه کنید.
- پارامتری وارد کنید که نتیجه خالی بدهد و رفتار کد فراخوان را بررسی کنید.
- یک مقدار Null یا رکورد تکراری آزمایشی اضافه و انطباق نتیجه با قاعده مستند را کنترل کنید.
- تعداد رکوردهای QueryDef ذخیرهشده را با Recordset بازشده در VBA مقایسه کنید.
- نام و نوع ستونهای نهایی مورد نیاز گزارش یا export را ثبت کنید.
خطاهای رایج و روش اصلاح
| نشانه خطا | علت و راهحل |
|---|---|
| تعداد ستونهای دو SELECT یکسان نیست | در تمام شاخهها تعداد عبارت برابر و ترتیب معنایی یکسان برگردانید. |
| عدم تطابق نوع یا تبدیل عجیب | نوع متن، عدد، تاریخ و Currency را هماهنگ کنید و فقط در صورت معتبر بودن از CStr یا CDate استفاده کنید. |
| نام ستون نهایی غیرمنتظره است | نامها از SELECT اول گرفته میشوند؛ alias روشن را در شاخه نخست تعریف کنید. |
| حذف رکورد تکراری | UNION سطر یکسان را حذف میکند؛ برای حفظ تمام رویدادها UNION ALL بهکار ببرید. |
| خطای ORDER BY | مرتبسازی را فقط پس از آخرین SELECT و با alias خروجی نهایی بنویسید. |
کارایی، ایمنی و نگهداری
برای اجرای مطمئن کوئری UNION در SQL اکسس بهتر است ابتدا یک نسخه آزمایشی از پایگاه داده بسازید و چند رکورد با مقادیر قابل تشخیص در آن قرار دهید. کوئری را پیش از اتصال به فرم، گزارش یا کد VBA مستقیماً در محیط Query Design اجرا کنید. این روش خطای طراحی SQL را از خطای اتوماسیون جدا میکند و بررسی نتیجه را سادهتر میسازد.
زبان SQL اکسس به SQL استاندارد نزدیک است، اما در نشانهگذاری تاریخ، wildcardها، پارامترها و موتور عبارتها تفاوتهایی دارد. هنگام کار با کوئری UNION در SQL اکسس ابتدا دستور را در خود Access آزمایش کنید. پس از تأیید نتیجه، همان منطق را به QueryDef ذخیرهشده یا رشته SQL در VBA منتقل کنید تا خطاهای نقلقول و نوع پارامتر زودتر آشکار شوند.
برای فیلدهای محاسباتی alias روشن انتخاب کنید. نام مستعار باید معنای خروجی را نشان دهد، نه اینکه فقط عبارت را تکرار کند. alias مناسب اتصال گزارش، خواندن Recordset در VBA و نگهداری پروژه را آسان میکند. اگر نام فیلد فاصله دارد یا با واژه رزروشده تداخل پیدا میکند، آن را داخل کروشه قرار دهید.
رفتار مقدار Null را از ابتدا مشخص کنید. توابع تجمیعی، شرطها، joinها و عبارتهای محاسباتی همگی Null را یکسان مدیریت نمیکنند. ابتدا تعیین کنید Null در منطق کسبوکار به معنی مقدار ناشناخته، نامرتبط یا صفر است. تابع Nz را فقط زمانی بهکار ببرید که جایگزینی Null با مقدار پیشفرض واقعاً درست باشد.
اعتبارسنجی ورودی را از اجرای کوئری جدا کنید. تاریخها، شناسهها و حدود عددی باید پیش از تخصیص به پارامتر بررسی شوند. متن واردشده توسط کاربر را در صورت وجود پارامتر به SQL نچسبانید. پارامترها علاوه بر کاهش خطاهای قالب تاریخ و جداکننده اعشاری، مشکل apostrophe در متن را نیز کنترل میکنند.
کارایی را با دادهای نزدیک به حجم واقعی اندازه بگیرید. کوئریای که روی بیست رکورد سریع است ممکن است روی صدها هزار رکورد کند شود. فیلدهای پرتکرار در join و فیلتر انتخابی را ایندکس کنید، روی فیلد ایندکسشده تابع غیرضروری اعمال نکنید و فقط ستونهایی را برگردانید که مرحله بعد واقعاً لازم دارد.
برنامه آزمون باید داده معمولی، مقدار مرزی، Null، رکورد تکراری و نتیجه خالی را پوشش دهد. بررسی کنید اگر هیچ رکوردی پیدا نشد، اگر یک گروه فقط یک عضو داشت یا اگر دو سطر مقدار مرتبسازی یکسان داشتند، خروجی همچنان قابل پیشبینی باشد. نتیجه مورد انتظار را پیش از بازنویسی کوئری ثبت کنید.
کوئری ذخیرهشده بخشی از مستندات پروژه است. برای QueryDef نام توصیفی انتخاب کنید، در ماژول VBA یک توضیح کوتاه درباره ورودی و خروجی بنویسید و هر کوئری را بر یک مسئولیت متمرکز نگه دارید. چنین کوئریای مستقیماً قابل آزمایش است و میتواند میان فرم، گزارش و کد مشترک باشد.
اگر خروجی کوئری برای گزارش مهم یا عملیات تغییر داده استفاده میشود، پارامترها و تعداد رکوردهای برگرداندهشده را ثبت کنید. لازم نیست داده حساس در log ذخیره شود. زمان اجرا، نام کوئری، خلاصه پارامترها و تعداد سطرها معمولاً برای عیبیابی کافی است.
کوئری UNION در SQL اکسس را بخشی از یک زنجیره پردازش داده ببینید. ورودی، شکل خروجی و مصرفکننده نتیجه باید روشن باشد. اینکه خروجی برای نمودار، گزارش، export به Excel یا مرحله ویرایش داده استفاده میشود، روی aliasها، ترتیب، سیاست Null و میزان جزئیات اثر مستقیم دارد.
تمرین مرحلهبهمرحله
تمرین را در سه نسخه بسازید. در نسخه اول فقط سطرهای خام را با join و فیلتر ضروری برگردانید. در نسخه دوم تکنیک اصلی این درس را اضافه و نتیجه را با داده کم کنترل کنید. در نسخه سوم پارامتر، alias، مرتبسازی و روال VBA را بیفزایید. هر نسخه را موقتاً با نام جدا ذخیره کنید تا علت هر تغییر در خروجی مشخص باشد.
در تمرین دوم فقط یک قاعده کسبوکار را تغییر دهید؛ برای نمونه بازه گزارش، حذف سفارشهای لغوشده، انتخاب دسته متفاوت یا تغییر خروجی از جزئیات به خلاصه. کوئری مناسب باید اجازه دهد این تغییر در یک پارامتر، شرط یا عبارت محاسباتی انجام شود و به بازنویسی چند بخش نامرتبط نیاز نداشته باشد.
در پایان کوئری را از دید توسعهدهنده دیگری بازبینی کنید. آیا بدون بازکردن فرمها میتوان جدولهای ورودی، پارامترها، ستونهای خروجی و سطح هر سطر را تشخیص داد؟ aliasهای مبهم را اصلاح، ستونهای بلااستفاده را حذف و در ماژول VBA یک توضیح کوتاه درباره فرضها ثبت کنید.
درسهای مرتبط این مجموعه
این درس پس از مباحث SELECT، WHERE، JOIN و ویرایش داده قرار میگیرد. برای مرور عملیات تغییر رکورد میتوانید مقاله ویرایش و حذف دادهها در SQL اکسس با VBA را بخوانید. پیشنهادهای لینک داخلی، درسهای بعدی این مجموعه را نیز تا زمان انتشار با وضعیت planned نگه میدارند.
پرسشهای متداول درباره کوئری UNION در SQL اکسس
کوئری UNION در SQL اکسس چه میکند؟
UNION سطرهای دو یا چند SELECT سازگار را در یک نتیجه قرار میدهد. تمام SELECTها باید تعداد ستون برابر با ترتیب یکسان داشته باشند و نوع ستونهای متناظر با یکدیگر سازگار باشد.
تفاوت UNION و UNION ALL چیست؟
UNION رکوردهای کاملاً تکراری را حذف میکند و برای مقایسه هزینه بیشتری دارد. UNION ALL تمام سطرها را نگه میدارد و معمولاً سریعتر است. حذف تکرار باید یک قاعده واقعی باشد، نه انتخاب پیشفرض.
نام ستونها در UNION چگونه تعیین میشود؟
نام خروجی از SELECT اول گرفته میشود. aliasهای پایدار را در شاخه اول تعریف کنید و در شاخههای بعد مقدارهایی با همان معنا و ترتیب برگردانید. گزارش و VBA نیز باید aliasهای شاخه اول را بخوانند.
آیا هر SELECT میتواند ORDER BY داشته باشد؟
در کوئری UNION اکسس معمولاً فقط یک ORDER BY پس از آخرین SELECT نوشته میشود. اگر شاخهای آمادهسازی خاص دارد، آن را بهصورت کوئری ذخیرهشده بسازید و خروجی آن را UNION کنید.
آیا UNION میتواند پارامتر داشته باشد؟
بله. پارامترها را یکبار در PARAMETERS تعریف و در تمام شاخههای لازم استفاده کنید. پیش از بازکردن نتیجه در VBA، مقدار آنها را در QueryDef ذخیرهشده تعیین کنید.
آیا UNION جایگزین JOIN است؟
خیر. UNION سطرهای سازگار را عمودی اضافه میکند، اما JOIN با تطبیق کلیدها ستونهای مرتبط را کنار هم قرار میدهد. انتخاب به شکل خروجی و پرسش دادهای بستگی دارد.
جمعبندی
پس از این درس میتوانید مجموعههای سازگار را تشخیص دهید، UNION یا UNION ALL را انتخاب کنید، نوع و alias را هماهنگ سازید، تمام شاخهها را پارامتری کنید و نتیجه را از VBA بخوانید.
روش قابل اعتماد، ساخت تدریجی است: SQL را با داده کنترلشده ثابت کنید، نوع پارامترها را صریح بنویسید، رفتار Null و داده تکراری را بیازمایید و سپس اتوماسیون را اضافه کنید. با این ترتیب، تغییر جدولها، فرمها یا نیاز گزارشگیری هزینه کمتری خواهد داشت.
بیشتر بخوانید
کوئری جدول متقاطع با TRANSFORM و PIVOT در SQL اکسس
کوئری پارامتری در SQL اکسس با QueryDef و VBA
زیرکوئری در SQL اکسس با IN، EXISTS و کوئری همبسته
توابع تجمیعی، GROUP BY و HAVING در SQL اکسس
ویرایش و حذف دادهها در SQL اکسس با VBA
آموزش SQL در Microsoft Access: انواع JOIN (Inner, Left, Right) و اتصال چند جدول
آموزش SQL در Microsoft Access: انواع ارتباط بین جداول و ایجاد رابطه چندبهچند با جدول واسط