مدیریت NULL در SQL اکسس؛ تفاوت Is Null و Nz با مقدار خالی
شماره تلفنی که هنوز ثبت نشده، با شمارهای که عمداً خالی گذاشته شده یکسان نیست؛ همانطور که تخفیف نامعلوم لزوماً تخفیف صفر نیست. در Microsoft Access مقدار NULL نشاندهنده نبود داده است و اشتباهگرفتن آن با صفر یا رشته خالی میتواند نتیجه گزارشهای مدیریتی و مالی را بهظاهر درست اما در واقع نادرست کند.
این درس در ادامه موضوعات WHERE، توابع تجمیعی و انواع داده قرار میگیرد و منطق ویژه مقادیر ناموجود را توضیح میدهد. شرط IS NULL، تابع Nz، رفتار محاسبات و روش خواندن فیلدهای خالی در DAO را با مثال میبینیم تا هنگام گزارشگیری معنای داده حفظ شود.
مفهوم و محدوده کاربرد
Null یک نشانگر برای مقدار ناشناخته یا موجودنبودن داده است، نه کلمه «Null». با صفر، False و رشته صفرطول تفاوت دارد. ممکن است مبلغی را هنوز ندانیم؛ این حالت با مبلغی که اندازهگیری شده و دقیقاً صفر است فرق دارد. برای کنترل کیفیت داده و گزارشهای مالی این تفاوت بنیادی است.
مقایسه با Null مانند مقایسه دو عدد معمولی نیست. عبارت Amount = Null رکوردهای ناموجود را پیدا نمیکند؛ برای چنین هدفی باید Amount Is Null و برای مقادیر موجود Amount Is Not Null نوشته شود. این منطق در WHERE و فیلد محاسباتی و حتی خروجی JOIN نیز اثر دارد.
تابع Nz(value, replacement) برای مقدار Null یک جایگزین مشخص برمیگرداند. مثلاً میتوان در یک گزارش عددی، تخفیف ناموجود را موقتاً صفر نشان داد؛ اما این تصمیم باید توجیه کسبوکار داشته باشد. اگر بدون توضیح چنین جایگزینی انجام شود، خواننده نمیفهمد عدد صفر واقعی بوده یا فقط برای نمایش ساخته شده است.
دادههای نمونه و فرضها
جدول Customers با فیلدهای CustomerID و CustomerName و Email و PhoneNumber و جدول Orders با OrderID و CustomerID و TotalAmount و DiscountAmount فرض میشود. برای DiscountAmount سه رکورد شامل صفر واقعی، تخفیف مثبت و Null قرار دهید. در Email هم یک رشته خالی و یک Null ثبت کنید تا روشن شود چرا یک شرط ساده برای بررسی تمام حالتهای «خالی» کافی نیست.
ساختار دستور و تفسیر آن
برای یافتن مقدار ناموجود از IS NULL یا IS NOT NULL استفاده کنید؛ به جای آن عبارت = Null ننویسید. اگر قرار است فیلد متنی هم Null و هم رشته خالی را پوشش دهد، دو شرط Email Is Null و Email = “” را با OR ترکیب کنید. توجه داشته باشید که ذخیره رشته خالی به تنظیمات همان فیلد وابسته است.
در محاسبه میتوان جایگزین را صریح تعیین کرد: Nz(DiscountAmount,0) یک فرض عددی و Nz(Email,””) یک فرض متنی است. حتی پارامتر اختیاری هم ممکن است Null باشد؛ بنابراین نمیتوان همیشه آن را با علامت مساوی با فیلد مقایسه کرد و انتظار نتیجه مناسب داشت.
SELECT CustomerID, CustomerName, Email
FROM Customers
WHERE Email IS NULL OR Email = "";
مثالهای گامبهگام
مثالها ابتدا داده ناموجود را آشکار میکنند، سپس جایگزینی کنترلشده را نشان میدهند و در پایان گزارش کیفیت اطلاعات تماس میسازند. ترتیب مهم است: نباید پیش از شمارش داده ناقص، همه مقادیر را به صفر یا رشته خالی تبدیل کرد.
شناسایی تخفیفهای ناموجود
این کوئری فقط تخفیفهای نامعلوم را برمیگرداند. سفارشی با تخفیف واقعی صفر حالت دیگری است و نباید همراه آن شمرده شود. پیش از تبدیل Null به صفر، تعداد تخفیفهای ناموجود را جدا ثبت و درباره سیاست اصلاح اطلاعات تصمیمگیری کنید.
SELECT OrderID, DiscountAmount FROM Orders WHERE DiscountAmount IS NULL;
نمایش مبلغ با جایگزین مشخص
نام مستعار ReportDiscount نشان میدهد خروجی با یک جایگزین ساخته شده است؛ فیلد اصلی DiscountAmount تغییر نمیکند. این روش تنها زمانی درست است که سیاست گزارش، نمایش تخفیف ناموجود به صورت صفر را مجاز بداند. در غیر این صورت باید ناشناخته بودن مبلغ را جداگانه نشان دهید.
SELECT OrderID, TotalAmount, Nz(DiscountAmount, 0) AS ReportDiscount FROM Orders;
پیداکردن دو نوع ایمیل خالی
فیلد متنی ممکن است بسته به تنظیماتش Null یا رشتهای با طول صفر داشته باشد. این دو در Datasheet شبیه به هم دیده میشوند. شرط ترکیبی برای استخراج فهرست اطلاعات تماس ناقص مناسب است، ولی هنگام سنجش کیفیت ثبت داده بهتر است تعداد هر وضعیت مستقل گزارش شود.
SELECT CustomerID, CustomerName FROM Customers WHERE Email IS NULL OR Email = "";
اجرای کوئری با VBA در اکسس
نمونه VBA رکوردهای مشتری را با DAO snapshot میخواند و برای ایمیل ناموجود علامت مشخصی نمایش میدهد. قبل از تبدیل مقدار به رشته، IsNull بررسی میشود. در نتیجه عملیات نمایش از داده خام جدا میماند و روال گزارشگیری هیچ رکوردی را در جدول تغییر نمیدهد.
کد در ماژول استاندارد Access و بر اساس جدول Customers اجرا میشود. میتوانید رفتار رشته خالی را مستقل از Null نمایش دهید؛ مثلاً یکی را «وارد نشده» و دیگری را «خالی ثبت شده» بنامید. چنین گزارشی به واحد ثبت اطلاعات کمک میکند منشأ مشکل را اصلاح کند، نه اینکه فقط خروجی هر گزارش را وصله بزند.
Option Explicit
Public Sub AuditMissingEmail()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim emailValue As Variant
On Error GoTo Fail
Set db = CurrentDb
Set rs = db.OpenRecordset( _
"SELECT CustomerID, Email FROM Customers ORDER BY CustomerID;", _
dbOpenSnapshot)
Do Until rs.EOF
emailValue = rs!Email.Value
If IsNull(emailValue) Then
Debug.Print rs!CustomerID, "<missing>"
ElseIf Len(CStr(emailValue)) = 0 Then
Debug.Print rs!CustomerID, "<empty>"
Else
Debug.Print rs!CustomerID, CStr(emailValue)
End If
rs.MoveNext
Loop
CleanUp:
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub
Fail:
Debug.Print Err.Number, Err.Description
Resume CleanUp
End Sub
کنترل نتیجه و شرایط مرزی
ابتدا تعداد تخفیفهای Null را از تخفیفهای صفر جدا کنید. سپس Count(*) و Count(DiscountAmount) را روی همان سفارشها مقایسه کنید؛ این دو لزوماً برابر نیستند، زیرا Count(field) مقدار Null را نمیشمارد. نوع عبارت پس از Nz و نحوه نمایش نتیجه در خروجی اکسل یا گزارش چاپی را نیز کنترل کنید.
خطاهای رایج و راهحل
خطاهای مربوط به Null گاهی به شکل جمع اشتباه یا حذف رکورد ظاهر میشوند و خطای Syntax ندارند. هم SQL و هم معنای جایگزین انتخابشده را بررسی کنید:
| نشانه یا علت | روش اصلاح |
|---|---|
| شرط Email = Null نتیجه ندارد | از Email IS NULL استفاده کنید؛ مساوی برای شناسایی Null مناسب نیست. |
| تخفیف صفر و ناموجود با هم شمارش میشوند | DiscountAmount = 0 و DiscountAmount IS NULL را جدا گزارش کنید. |
| Count(*) با Count(field) برابر نیست | تابع دوم Null را نمیشمارد؛ این تفاوت معمولاً رفتار درست تابع است. |
| Nz اطلاعات ناقص را پنهان میکند | پیش از جایگزینی، مقادیر ناموجود را بشمارید و خروجی مشتقشده را مشخص کنید. |
بهترین روشها برای کوئری قابل اعتماد
در مستندات مشخص کنید مبلغ ناموجود یعنی «نامعلوم»، «نامرتبط»، «هنوز ثبت نشده» یا «صفر واقعی». فقط بعضی از این موارد جایگزینی با صفر را توجیه میکنند. اگر تفاوت وضعیتها مهم است، فیلد وضعیت مستقل ایجاد کنید تا تمام معنی از یک مقدار Null حدس زده نشود.
عادت نکنید روی همه فیلدها Nz اعمال کنید. این کار ممکن است نقص کیفیت داده را پنهان کند و پس از جایگزینی دیگر نتوان مقدارهای Null را جداگانه شمارش کرد. یک کوئری مستقل برای ممیزی اطلاعات ناقص نگه دارید و وقتی گزارش خلاصه حساس است، تعداد رکوردهای کامل و ناقص را کنار هم نشان دهید.
در توابع تجمیعی، معنی هر تابع را جداگانه بررسی کنید. Count(*) سطرها را میشمارد، Count(field) مقادیر غیر Null را و Sum نیز Null را در جمع منظور نمیکند. اگر گروهی هیچ مقدار غیر Null نداشته باشد، شیوه نمایش را آگاهانه انتخاب کنید و آن را با مقدار واقعی ذخیرهشده در منبع یکی ندانید.
برای پیدا کردن Null نباید از مساوی استفاده کرد. در SQL اکسس نوشتن IS NULL صریح و ضروری است. در LEFT JOIN مقدار Null مربوط به طرف بدون انطباق میتواند یعنی اصلاً رکورد مرتبط وجود ندارد؛ این الزاماً به معنای خالیبودن یک فیلد در رکورد مرتبط نیست.
اگر روی ستونی ایندکس وجود دارد، پیچیدن آن در تابعی مانند Nz ممکن است بهرهگیری از ایندکس را دشوار کند. شرط مستقیم IS NULL یا مقایسه عادی را با عبارت تابعی مقایسه و عملکرد را با داده واقعی بسنجید. هیچ بهینهسازی نباید معنای داده را قربانی سرعت کند.
آزمایشگاه تمرین
کوئری کنترل کاملبودن داده بسازید که CustomerID و CustomerName و یک فیلد محاسباتی EmailStatus برگرداند. برای Null و رشته خالی و متن موجود سه برچسب متفاوت در نظر بگیرید. در کوئری بعدی تعداد هر وضعیت را بشمارید و مطمئن شوید مجموع وضعیتها با تعداد کل مشتریها برابر است.
گزارش سفارشها را طوری بنویسید که Sum(DiscountAmount) و Count(DiscountAmount) و Count(*) کنار هم دیده شوند. از شخص دیگری بخواهید بدون دیدن SQL معنای هر عدد را توضیح دهد. اگر Null را با صفر واقعی اشتباه گرفت، پیش از انتشار گزارش، عنوان ستون و تعریف داده را اصلاح کنید.
درسهای مرتبط
در درس WHERE شرط رکوردی را یاد گرفتهاید، در QueryDef ورودی اختیاری را به کوئری میرسانید و با کوئری ذخیرهشده، ممیزی داده ناقص را قابل تکرار میکنید. این موضوعات پایه مدیریت درست Null هستند.
- کاربرد WHERE در SQL اکسس: آموزش SQL در Microsoft Access: کاربرد جزء WHERE در SQL
- کوئری پارامتری با QueryDef: کوئری پارامتری در SQL اکسس با QueryDef و VBA
- مرتبسازی ORDER BY در اکسس: آموزش مرتبسازی نتایج کوئری با ORDER BY در SQL اکسس
پرسشهای متداول
مدیریت NULL در SQL اکسس از چه مفهومی شروع میشود؟
Null یعنی برای آن فیلد مقدار معتبری موجود نیست. این وضعیت با صفر، False، رشته خالی یا متن «Null» تفاوت دارد. برای مثال ممکن است تخفیف سفارشی واقعاً صفر باشد یا هنوز تخفیف آن ثبت نشده باشد. هر دو در گزارش ظاهری شبیه دارند، ولی از نظر کنترل اطلاعات و تصمیم مدیریتی یکسان نیستند.
چرا شرط Field = Null رکوردهای خالی را نمییابد؟
مقدار Null در مقایسه معمولی مثل عدد یا متن رفتار نمیکند. بنابراین Field = Null روش مناسبی برای پیدا کردن مقدار ناشناخته نیست. در SQL اکسس باید از IS NULL و IS NOT NULL استفاده شود. اگر فیلد اجازه ذخیره رشته خالی داشته باشد، آن حالت نیز باید با شرطی جداگانه مانند Field = “” بررسی شود.
چه زمانی استفاده از Nz(value,0) درست است؟
وقتی یک قاعده کسبوکار صریح اجازه دهد مقدار ناموجود در محاسبه یا نمایش معادل صفر باشد، Nz(value,0) مناسب است. مثلاً ممکن است سیاست گزارش اجازه دهد تخفیف اختیاری ناموجود صفر در نظر گرفته شود. اما برای بدهی یا مبلغ واقعاً نامعلوم چنین فرضی گمراهکننده است. فیلد اصلی را حفظ و مقدار جایگزین گزارش را با نام مستعار جدا نشان دهید.
آیا Null و رشته خالی در اکسس یکسان هستند؟
خیر. Null نشاندهنده نبود مقدار است؛ رشته خالی یک مقدار متنی ذخیرهشده با طول صفر محسوب میشود. اینکه فیلد Short Text چنین رشتهای را بپذیرد به تنظیمات آن بستگی دارد. برای بررسی اطلاعات تماس میتوان هر دو را استخراج کرد، اما بهتر است جدا شمارش شوند. برای اولی IS NULL و برای دومی = “” کاربرد دارد.
آیا Count(column) رکوردهای Null را میشمارد؟
Count(column) فقط مقدارهای غیر Null همان ستون را میشمارد، اما Count(*) تعداد سطرها را برمیگرداند. اگر ده سفارش داشته باشیم و تخفیف دو سفارش Null باشد، عدد اول هشت و عدد دوم ده خواهد بود. این تفاوت خطا نیست؛ هر تابع پرسش دیگری را پاسخ میدهد. در گزارش کاملبودن داده بهتر است هر دو را کنار هم بیاورید.
در VBA اکسس مقدار متنی Null را چگونه بخوانیم؟
مقدار فیلد را ابتدا در Variant بخوانید و قبل از تبدیل به String یا اجرای تابع متنی، IsNull را بررسی کنید. اگر مقدار ناموجود بود برچسب مشخص نمایش دهید و در غیر این صورت رشته خالی را مستقل ارزیابی کنید. Recordset را در مسیر موفق و خطا ببندید. روال نمایش نباید هنگام آمادهسازی گزارش، اطلاعات اصلی جدول را بیسر و صدا تغییر دهد.
جمعبندی
مدیریت NULL در SQL اکسس علاوه بر دستور درست، نیازمند تصمیم روشن درباره معنای داده است. برای رکوردهای فاقد مقدار از IS NULL استفاده کنید، رشته خالی را جدا بشناسید و Nz را فقط هنگامی به کار ببرید که جایگزین از نظر کسبوکار موجه باشد.
بهترین آزمون، دادهای است که در آن Null و صفر و متن خالی سه نتیجه متفاوت ایجاد کنند. اگر کوئری و عنوانهای گزارش در این شرایط هم درست باشند، استفاده از خروجی در فرم و اتوماسیون با اطمینان بیشتری انجام میشود.
بیشتر بخوانید
محدودیتها و قوانین اعتبارسنجی در SQL اکسس به زبان ساده
آموزش حذف نتایج تکراری با دستور DISTINCT در SQL اکسس
آموزش کار با کوئریهای ذخیرهشده و Viewها در SQL اکسس
آموزش مرتبسازی نتایج کوئری با ORDER BY در SQL اکسس
انواع داده و تعریف فیلدها در SQL اکسس: راهنمای جامع