ESC را فشار دهید تا بسته شود

زمیوس آموزش، یادگیری و سرگرمی

ORA‑۰۱۷۲۲: invalid number — علت و رفع خطای تبدیل اشتباه عددی در Oracle SQL

اگر با پایگاه‌داده‌ی اوراکل (Oracle Database) کار کرده باشی، احتمالاً با خطای معروف زیر برخورد کرده‌ای:

				
					ORA-01722: invalid number

				
			

این ارور یکی از متداول‌ترین خطاهای SQL در محیط Oracle است، و تقریباً همه‌ی توسعه‌دهنده‌ها و DBAها حداقل یک‌بار با آن دردسر داشته‌اند.

ولی واقعاً دلیلش چیست؟ چرا Oracle چنین خطایی می‌دهد و چطور باید آن را برطرف کنیم؟

در ادامه آموزش Oracle در بخش آموزش خطاهای اوراکلی همه چیز را توضیح می‌دهم، با مثال‌های واقعی، تا همیشه بتوانی بفهمی مشکل از کجاست و چطور از تکرارش جلوگیری کنی.

اگر توسعه‌دهنده یا معمار پایگاه داده‌ی Oracle هستی، احتمالاً با خطای معروف زیر روبه‌رو شده‌ای:
				
					ORA‑۰۱۴۰۰: cannot insert NULL into ("SCHEMA"."TABLE"."COLUMN")
				
			

این خطا یکی از رایج‌ترین خطاهایی است که هنگام اجرای دستور INSERT یا UPDATE رخ می‌دهد.

پیشنهاد می کنم این مقاله زیر رو حتما مطالعه کنی.

در این مقاله شما می خوانید

این خطا دقیقاً زمانی اتفاق می‌افتد که Oracle در حال تبدیل یک مقدار متنی (String) به نوع عددی (Number) است،

اما محتوای رشته با فرمت عددی سازگار نیست.

به زبان ساده‌تر، Query تو جایی باعث می‌شود Oracle بخواهد 'ABC' را به عدد تبدیل کند!

البته معمولاً خودت این تبدیل را ننوشته‌ای، چون در اکثر موارد این تبدیل به‌صورت ضمنی (Implicit Conversion) انجام می‌شود.

وقتی در SQL دو نوع داده‌ی متفاوت را مقایسه یا ترکیب می‌کنی (مثلاً VARCHAR2 و NUMBER

Oracle تصمیم می‌گیرد یکی را به دیگری تبدیل کند.

🔸 قوانین داخلی اوراکل:

  1. اگر یکی از طرفین NUMBER باشد، Oracle مقدار متنی (VARCHAR2) را به عدد تبدیل می‌کند.
  2. اگر حتی یک رکورد مقدار غیرعددی داشته باشد، Query کلًا از کار می‌افتد.
  3. این تبدیل فقط در لحظه اجرای Query انجام می‌شود (نه هنگام Parse).
				
					SELECT TO_NUMBER('12A3') FROM dual;

				
			

در اینجا رشته '۱۲A3' شامل کاراکتر حرفی است، پس تبدیل شکست می‌خورد و نتیجه:

ORA-01722: invalid number

۱. مقایسه‌ی ستون‌های ناسازگار

				
					SELECT e.emp_id, t.emp_id
FROM emp e
JOIN temp_emp t
  ON e.emp_id = t.emp_id;

				
			

در ظاهر ساده به‌نظر می‌رسد، اما اگر یکی از جداول (temp_emp) ستون emp_id را به‌صورت VARCHAR2 داشته باشد

و حتی فقط یک مقدار غیرعددی مثل '۱۲A' در آن باشد، کل Query با همان خطا متوقف می‌شود.

۲. شرط اشتباه در WHERE

				
					SELECT * 
FROM employees 
WHERE emp_code = 123;

				
			

اگر emp_code از نوع VARCHAR2 باشد، Oracle لازمه یکی از طرفین را تبدیل کند.

در این حالت مقدار 'A123' باعث ارور ORA‑۰۱۷۲۲ می‌شود.

۳. تبدیل ناخواسته در تابع

				
					SELECT TO_NUMBER(emp_code)
FROM employees;

				
			

اگر حتی یکی از رکوردها مقدار غیرعددی داشته باشد، تابع شکست می‌خورد.

در Oracle، ارور سطح Query است، یعنی یک سطر اشتباه باعث توقف کل اجرای دستور می‌شود.

می‌توانی با الگوهای منظم (REGEXP_LIKE) داده‌های آلوده را پیدا کنی:

				
					SELECT emp_code
FROM employees
WHERE REGEXP_LIKE(emp_code, '[^0-9]');

				
			

یا اگر مقادیر اعشاری هم وجود دارد:

				
					WHERE NOT REGEXP_LIKE(emp_code, '^\d+(\.\d+)?$');

				
			

۱. فیلتر داده‌های معتبر پیش از تبدیل

				
					SELECT TO_NUMBER(emp_code)
FROM employees
WHERE REGEXP_LIKE(emp_code, '^\d+$');

				
			

۲. استفاده از CASE برای تبدیل امن

				
					SELECT 
  CASE 
    WHEN REGEXP_LIKE(emp_code, '^\d+$') 
    THEN TO_NUMBER(emp_code)
  END AS emp_num
FROM employees;

				
			

۳. هم‌نوع‌سازی داده‌ها در مقایسه

				
					SELECT *
FROM emp e
JOIN temp_emp t
  ON TO_CHAR(e.emp_id) = t.emp_id;

				
			

یا این‌طور:

				
					ON e.emp_id = TO_NUMBER(t.emp_id)
AND REGEXP_LIKE(t.emp_id, '^\d+$');

				
			
  • از REGEXP فقط در مرحلهٔ پاک‌سازی استفاده کن (نه در Query اصلی، چون کمی کند است).
  • در طراحی اسکیمای دیتابیس نوع فیلدها را دقیق انتخاب کن (عدد، عدد باشد. متن، متن).
  • در ETL یا APIها قبل از Insert داده را Validate کن تا Oracle مجبور به حدس datatype نشود.

سوالات متداول درباره رفع خطای ORA‑۰۱۷۲۲ در اوراکل

وقتی Oracle هنگام اجرای Query می‌خواهد یک مقدار متنی (مثل '۱۲A' یا '۱ ۲۳') را به عدد تبدیل کند اما نمی‌تواند، خطای ORA‑۰۱۷۲۲: invalid number نمایش داده می‌شود.

این نوع خطا ناشی از تبدیل ضمنی نادرست (Implicit Conversion) بین نوع داده‌های متفاوت مانند VARCHAR2 و NUMBER است.

Oracle فقط اولین رکورد مشکل‌دار را گزارش می‌کند و نام سطر را نمی‌گوید.

برای یافتن داده‌ی اشتباه می‌توان از دستور زیر استفاده کرد:

SELECT emp_code FROM employees
WHERE REGEXP_LIKE(emp_code, ‘[^0-9]’);

این Query سطرهایی را پیدا می‌کند که شامل مقادیر غیرعددی هستند و عامل خطا محسوب می‌شوند.

در تبدیل ضمنی (Implicit Conversion)، Oracle خودش تصمیم می‌گیرد که نوع داده را تغییر دهد؛ اما در TO_NUMBER()، برنامه‌نویس این تبدیل را به‌صورت صریح (Explicit) انجام می‌دهد.

روش دوم امن‌تر است چون کنترل کامل بر روی رفتار تبدیل دارد و از بروز خطای ORA‑۰۱۷۲۲ جلوگیری می‌کند.

۱. نوع داده‌ی ستون‌ها را از ابتدا درست طراحی کن (NUMBER برای عددی‌ها، VARCHAR2 برای متن‌ها).

۲. داده‌های ورودی را با الگوهای منظم (RegEx) بررسی کن:

   REGEXP_LIKE(col, '^\d+$')

۳. از تبدیل صریح (TO_CHAR, TO_NUMBER) استفاده کن و هیچگاه به Oracle اجازه تصمیم خودکار نده.

۴. در فرایند ETL، داده‌ی ناسالم را قبل از Insert یا Merge فیلتر کن تا کل Query فریز نشود.

سناریو علت خطا راه‌حل پیشنهادی
مقایسه ستون NUMBER با VARCHAR2 تبدیل ضمنی نامعتبر توسط Oracle یکسان‌سازی نوع داده پیش از JOIN
داده متنی آلوده وجود کاراکتر غیرعددی در String فیلتر با REGEXP_LIKE یا پاک‌سازی قبل از تبدیل
تبدیل ضمنی در WHERE Oracle سمت اشتباه را تبدیل می‌کند استفاده از TO_CHAR یا TO_NUMBER صریح
طراحی ضعیف اسکیمای داده ذخیره عدد در ستون متنی اصلاح datatype در مرحله طراحی جدول
  • خطای ORA‑۰۱۷۲۲: invalid number نشانه‌ی این است که بخشی از داده‌ات یا طراحی دیتاتایپ اشتباه است.

    این خطا به جای اینکه ترسناک باشد، در واقع به تو می‌گوید:

    “کد یا دیتا باید تمیزتر و دقیق‌تر تعریف شود.”

    با شناخت تبدیل‌های ضمنی Oracle و استفاده از الگوهای امن (TO_NUMBER، TO_CHAR, ‌REGEXP_LIKE)

    می‌توانی اجرای Queryهای خود را ایمن و بدون خطا نگه داری.

📥 اگر سوالی داری در مورد رفع خطای ORA‑۰۱۷۲۲ در اوراکل داری، در بخش کامنت‌ها بپرس.

میثم راد

من یه برنامه نویسم که حسابی با دیتابیس اوراکل رفیقم! از اونایی ام که تا چیزی رو کامل نفهمم،ول کن نیستم، یادگرفتن برام مثل بازیه، و نوشتن اینجا کمک می کنه تا چیزایی که یاد گرفتم رو با بقیه به شریک بشم، با هم پیشرفت کنیم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *