ORA-00902: Invalid Datatype - Fix Column Type Errors
ORA-00902: Invalid Datatype
Section titled “ORA-00902: Invalid Datatype”Error Overview
Section titled “Error Overview”Error Text: ORA-00902: invalid datatype
The ORA-00902 error is raised when Oracle encounters an unrecognized or unsupported data type in a SQL statement. This most commonly occurs in CREATE TABLE, ALTER TABLE, or CAST expressions where a data type name is misspelled, borrowed from another database platform, or used in an incompatible Oracle version.
Common Causes
Section titled “Common Causes”1. Misspelled Data Type Names
Section titled “1. Misspelled Data Type Names”INTERGERinstead ofINTEGERVARCHA2instead ofVARCHAR2NUMERinstead ofNUMBERBOOLinstead of using aNUMBER(1)orCHAR(1)workaround
2. Non-Oracle Data Types Used
Section titled “2. Non-Oracle Data Types Used”- MySQL-specific types:
TINYINT,MEDIUMINT,BIGINT,TEXT,ENUM - SQL Server types:
NVARCHAR(MAX),BIT,DATETIME2,UNIQUEIDENTIFIER - PostgreSQL types:
BOOLEAN,SERIAL,BYTEA,UUID
3. Version-Specific Types Used on Older Databases
Section titled “3. Version-Specific Types Used on Older Databases”JSONtype introduced in Oracle 21c / partially in 12.2 — not available in 11g/12.1VECTORtype introduced in Oracle 23aiBOOLEANSQL-level type introduced in Oracle 23ai
4. Incorrect Syntax in CAST or CONVERT
Section titled “4. Incorrect Syntax in CAST or CONVERT”- Invalid target type inside
CAST(expr AS type) - Missing precision where required (e.g.,
VARCHARwithout length)
Diagnostic Queries
Section titled “Diagnostic Queries”List All Valid Oracle Data Types
Section titled “List All Valid Oracle Data Types”-- View built-in types available in this database versionSELECT type_name, typecodeFROM all_typesWHERE predefined = 'YES'ORDER BY type_name;
-- Check database version to understand type availabilitySELECT banner FROM v$version WHERE banner LIKE 'Oracle%';Find Tables with Potentially Problematic Column Types
Section titled “Find Tables with Potentially Problematic Column Types”-- Audit all column data types in a schemaSELECT owner, table_name, column_name, data_type, data_length, data_precision, data_scale, nullableFROM all_tab_columnsWHERE owner = 'HR'ORDER BY table_name, column_id;Check Recent DDL Errors in Audit Trail
Section titled “Check Recent DDL Errors in Audit Trail”-- Find recent DDL failures that may indicate bad type usageSELECT event_timestamp, db_user_name, sql_text, return_codeFROM unified_audit_trailWHERE return_code = 902 AND event_timestamp > SYSTIMESTAMP - INTERVAL '7' DAYORDER BY event_timestamp DESC;Check Object Types in Schema
Section titled “Check Object Types in Schema”-- Review user-defined types for conflictsSELECT type_name, typecode, attributes, methods, statusFROM all_typesWHERE owner = 'HR'ORDER BY type_name;Step-by-Step Resolution
Section titled “Step-by-Step Resolution”1. Correct Misspelled Type Names
Section titled “1. Correct Misspelled Type Names”-- WRONG-- CREATE TABLE orders (-- order_id INTERGER,-- status VARCHA2(20),-- amount NUMER(10,2)-- );
-- CORRECTCREATE TABLE orders ( order_id INTEGER, status VARCHAR2(20), amount NUMBER(10,2));2. Replace Non-Oracle Types with Oracle Equivalents
Section titled “2. Replace Non-Oracle Types with Oracle Equivalents”-- Migration mapping from MySQL/SQL Server to Oracle
-- WRONG (MySQL types)-- CREATE TABLE products (-- id BIGINT AUTO_INCREMENT,-- name TEXT,-- active BOOL,-- price DECIMAL(10,2)-- );
-- CORRECT (Oracle equivalents)CREATE TABLE products ( id NUMBER(19) GENERATED ALWAYS AS IDENTITY, name CLOB, -- TEXT -> CLOB (or VARCHAR2 up to 32767) active NUMBER(1,0), -- BOOL -> NUMBER(1,0) check (0 or 1) price NUMBER(10,2) -- DECIMAL is a synonym for NUMBER in Oracle);
-- WRONG (SQL Server types)-- CREATE TABLE users (-- user_id UNIQUEIDENTIFIER,-- created DATETIME2,-- flags BIT-- );
-- CORRECTCREATE TABLE users ( user_id RAW(16), -- UNIQUEIDENTIFIER -> RAW(16) or use SYS_GUID() created TIMESTAMP, -- DATETIME2 -> TIMESTAMP flags NUMBER(1,0) -- BIT -> NUMBER(1,0));3. Fix Version-Specific Type Usage
Section titled “3. Fix Version-Specific Type Usage”-- Check Oracle version before using newer typesSELECT version FROM v$instance;
-- Oracle 23ai: BOOLEAN is now a native SQL type-- CREATE TABLE flags (is_active BOOLEAN); -- Only valid 23ai+
-- For 19c and earlier: use NUMBER(1) with a check constraintCREATE TABLE flags ( is_active NUMBER(1,0) DEFAULT 0 NOT NULL, CONSTRAINT chk_is_active CHECK (is_active IN (0, 1)));
-- Oracle 21c+: JSON is a native type-- For older versions, store JSON as CLOB with IS JSON constraintCREATE TABLE json_docs ( id NUMBER GENERATED ALWAYS AS IDENTITY, payload CLOB, CONSTRAINT chk_json CHECK (payload IS JSON));4. Fix CAST Expression with Invalid Type
Section titled “4. Fix CAST Expression with Invalid Type”-- WRONG: VARCHAR is not a valid standalone type in some contexts-- SELECT CAST(hire_date AS VARCHAR) FROM employees;
-- CORRECTSELECT CAST(hire_date AS VARCHAR2(30)) FROM employees;
-- WRONG: FLOAT without precision when used in CAST-- SELECT CAST(salary AS FLOAT) FROM employees;
-- CORRECTSELECT CAST(salary AS FLOAT(10)) FROM employees;-- orSELECT CAST(salary AS NUMBER(10,2)) FROM employees;5. Fix ALTER TABLE Column Type Changes
Section titled “5. Fix ALTER TABLE Column Type Changes”-- Check current column definition before alteringSELECT column_name, data_type, data_length, data_precision, data_scaleFROM user_tab_columnsWHERE table_name = 'EMPLOYEES' AND column_name = 'PHONE_NUMBER';
-- WRONG-- ALTER TABLE employees MODIFY phone_number TEXT;
-- CORRECTALTER TABLE employees MODIFY phone_number VARCHAR2(50);Prevention Strategies
Section titled “Prevention Strategies”1. Use a Type Reference Script Before Migrations
Section titled “1. Use a Type Reference Script Before Migrations”-- Standard Oracle type reference for migration work-- Run this before writing DDL for a new schema
-- Numeric types-- NUMBER(p,s) : exact numeric, p=precision, s=scale-- FLOAT(p) : binary float approximation-- BINARY_FLOAT : 32-bit IEEE 754-- BINARY_DOUBLE : 64-bit IEEE 754-- INTEGER : synonym for NUMBER(38)
-- Character types-- VARCHAR2(n) : variable-length up to n bytes (max 4000 SQL / 32767 PL/SQL)-- CHAR(n) : fixed-length, padded with spaces-- NVARCHAR2(n) : Unicode variable-length-- NCHAR(n) : Unicode fixed-length-- CLOB : character large object-- NCLOB : Unicode character large object
-- Date/time types-- DATE : stores date and time to the second-- TIMESTAMP : sub-second precision-- TIMESTAMP WITH TIME ZONE-- TIMESTAMP WITH LOCAL TIME ZONE-- INTERVAL YEAR TO MONTH-- INTERVAL DAY TO SECOND
-- Binary types-- RAW(n) : variable-length raw binary, up to n bytes-- BLOB : binary large object
SELECT 'Type reference loaded' FROM dual;2. Validate DDL in Dev/Test First
Section titled “2. Validate DDL in Dev/Test First”-- Always run CREATE TABLE in a test schema firstCREATE TABLE test_schema.validate_types ( col1 NUMBER(10,2), col2 VARCHAR2(100), col3 DATE, col4 TIMESTAMP, col5 CLOB);
-- Drop the test table after validationDROP TABLE test_schema.validate_types PURGE;3. Wrap DDL in Exception Handlers During Migration Scripts
Section titled “3. Wrap DDL in Exception Handlers During Migration Scripts”BEGIN EXECUTE IMMEDIATE ' CREATE TABLE new_table ( id NUMBER GENERATED ALWAYS AS IDENTITY, name VARCHAR2(200), status CHAR(1) ) '; DBMS_OUTPUT.PUT_LINE('Table created successfully');EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('DDL failed: ' || SQLERRM); RAISE;END;/4. Keep a Cross-Platform Type Mapping Reference
Section titled “4. Keep a Cross-Platform Type Mapping Reference”TINYINT/SMALLINT→NUMBER(5,0)INT/INTEGER/BIGINT→NUMBER(10,0)/NUMBER(19,0)BOOLEAN/BIT→NUMBER(1,0)with CHECK constraint (pre-23ai)TEXT/NTEXT→CLOB/NCLOBDATETIME/TIMESTAMP→DATEorTIMESTAMPUNIQUEIDENTIFIER→RAW(16)AUTO_INCREMENT/IDENTITY→GENERATED ALWAYS AS IDENTITY
Related Errors
Section titled “Related Errors”- ORA-00900 - Invalid SQL statement
- ORA-00907 - Missing right parenthesis
- ORA-00955 - Name already used by existing object
- ORA-02267 - Column type incompatible with referenced column
Emergency Response
Section titled “Emergency Response”Quick Fixes
Section titled “Quick Fixes”-
Identify the offending column type immediately
-- Check the exact error position using DBMS_SQLDECLAREv_c INTEGER := DBMS_SQL.OPEN_CURSOR;BEGINDBMS_SQL.PARSE(v_c,'CREATE TABLE t (id BIGINT)', -- replace with your DDLDBMS_SQL.NATIVE);EXCEPTIONWHEN OTHERS THENDBMS_OUTPUT.PUT_LINE(SQLERRM);DBMS_SQL.CLOSE_CURSOR(v_c);END;/ -
Check if a similar table already exists with valid types
SELECT column_name, data_type, data_lengthFROM all_tab_columnsWHERE table_name = UPPER('&your_table')ORDER BY column_id; -
Review migration script for vendor-specific types
-- Search for common non-Oracle types in your DDL file-- grep -iE "(TINYINT|BIGINT|NVARCHAR\(MAX\)|DATETIME2|BOOLEAN|TEXT|BIT)" migration.sqlSELECT 'Check migration script for non-Oracle type names' FROM dual;
Post-Resolution Cleanup
Section titled “Post-Resolution Cleanup”-- Verify new table structure is correct after fixSELECT column_name, data_type, data_length, data_precision, data_scale, nullableFROM user_tab_columnsWHERE table_name = 'YOUR_TABLE'ORDER BY column_id;
-- Confirm table is accessibleSELECT COUNT(*) FROM your_table;