---
title: "SQL Server to Oracle data types"
description: "Every SQL Server data type that Oracle stores differently, what the converter writes for it, when, and the report line."
canonical: https://intosql.com/docs/types/sql-server-to-oracle
last_updated: 2026-10-15
---

# SQL Server to Oracle data types

Each row is a type from SQL Server that Oracle stores differently: what the Oracle script gets, why, and the line the report writes about it. The rows come from the converter's own rules, so this page matches what it does.

**Convert in the browser:** [SQL Server to Oracle](/sql-server-to-oracle) opens the converter set up for this pair. The [SQL Server to Oracle migration guide](/docs/migrations/sql-server-to-oracle) covers dumping, loading and the rules for keys, indexes and names.

A report line is a fix when the converter changed something and lists it, or a problem when a value or object is worth a look.

## Numbers

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| decimal(p,s), money, smallmoney | NUMBER(p,s); money as NUMBER(19,4) | NUMBER holds 38 digits, as decimal does, so every value is exact. | None |

## Booleans and bits

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| bit | NUMBER(1) with a CHECK of 0 and 1 | Oracle 21c has no boolean column type; 1 and 0 keep the values on every version. | None |

## Text

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| char(n), varchar(n), nchar(n), nvarchar(n) | VARCHAR2(n CHAR), counting characters | Lengths count characters as SQL Server's nvarchar does. | None |
| varchar(max), nvarchar(max), text, ntext | VARCHAR2(4000 CHAR) when every value fits 4000 bytes, else CLOB | A VARCHAR2 holds 4000 bytes by default and Oracle can't index a CLOB, so text keeps VARCHAR2 when its values fit and is a CLOB when they don't. | `text_as_lob` (fix) |
| empty strings and empty binary values | NULL | Oracle stores an empty string as NULL, so a value that was ' reads back as NULL. The report counts them per column. | `empty_string_null` (problem) |
| NUL characters in text | kept | VARCHAR2 and CLOB can hold a NUL character, so the value is copied as it is. | None |
| text that isn't valid in its encoding | the bad bytes as the replacement character | The script is UTF-8 and every value has to be valid text. | `invalid_utf8_replaced` (problem) |

## Dates and times

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| datetime, datetime2, smalldatetime | TIMESTAMP(p) | A datetime is a wall-clock reading, like Oracle's TIMESTAMP, which keeps up to nine digits of a second. date becomes DATE, which also holds a time of day that stays at midnight. | None |
| datetimeoffset | TIMESTAMP WITH TIME ZONE, with each value's offset | Oracle keeps the offsets from -12:00 to +14:00; a value with an offset beyond -12:00 is written in UTC, the same instant. | None |
| time | INTERVAL DAY TO SECOND from midnight | Oracle has no time-of-day type; an interval from midnight holds every value. | None |
| dates that aren't valid | NULL | A value that isn't a date becomes NULL and the report counts it. | `date_out_of_range` (problem) |

## Binary

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| binary, varbinary, image | RAW(n) and BLOB | Bytes stay bytes. | None |
| rowversion, timestamp | BLOB, empty | SQL Server sets a row version by itself and SSMS scripts no values for it. | `rowversion_empty` (fix) |

## JSON, spatial and other types

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| json (SQL Server 2025) | CLOB | The same JSON values, which Oracle's JSON functions read. | None |
| uniqueidentifier | VARCHAR2(36) | The same identifiers, written in lowercase. | None |
| geometry, geography | BLOB with SQL Server's own bytes | SSMS writes spatial values in SQL Server's serialization, which is kept byte for byte. | `spatial_as_native` (fix) |
| xml, sql_variant, hierarchyid, vector | VARCHAR2 or CLOB with each value's text | Oracle has no equivalent type; xml and sql_variant keep each value's text and hierarchyid its path, such as /1/2/. | `type_replaced` (fix) |
| types IntoSQL doesn't know | CLOB | Text holds any value; change the type after loading. | `unknown_type` (problem) |

## Counters and identities

| In SQL Server | In Oracle | Why | Report line |
| --- | --- | --- | --- |
| IDENTITY | GENERATED BY DEFAULT ON NULL AS IDENTITY, continuing after the highest id | The copied ids load as they are, and the counter continues after the highest one. | None |

## Other pairs

- SQL Server into [PostgreSQL](/docs/types/sql-server-to-postgresql), [MySQL](/docs/types/sql-server-to-mysql), [MariaDB](/docs/types/sql-server-to-mariadb), [SQLite](/docs/types/sql-server-to-sqlite), [SQL Server](/docs/types/sql-server-to-sql-server)
- Into Oracle from [MySQL](/docs/types/mysql-to-oracle), [MariaDB](/docs/types/mariadb-to-oracle), [PostgreSQL](/docs/types/postgresql-to-oracle), [SQLite](/docs/types/sqlite-to-oracle), [Oracle](/docs/types/oracle-to-oracle)
- [Every pair](/docs/types#from-one-database-to-another)
