DiagramDB / SQL Data Types

SQL Data Types

The same idea has a different name in every database. Find the type you need and its equivalent in MySQL, PostgreSQL, SQL Server, Oracle and SQLite.

What you wantMySQLPostgreSQLSQL ServerOracleSQLiteNotes
Small integerSMALLINTSMALLINTSMALLINTNUMBER(5)INTEGER−32,768 to 32,767 (2 bytes).
IntegerINTINTEGERINTNUMBER(10)INTEGER−2,147,483,648 to 2,147,483,647 (4 bytes). The default for ids in small tables.
Big integerBIGINTBIGINTBIGINTNUMBER(19)INTEGER±9.2 quintillion (8 bytes). Use for ids that may pass 2 billion.
Auto-increment idINT AUTO_INCREMENTINTEGER GENERATED ALWAYS AS IDENTITY (or SERIAL)INT IDENTITY(1,1)NUMBER GENERATED AS IDENTITYINTEGER PRIMARY KEYSQLite’s INTEGER PRIMARY KEY is an alias for the rowid.
Exact decimalDECIMAL(p,s)NUMERIC(p,s)DECIMAL(p,s)NUMBER(p,s)NUMERICExact. Use for money: DECIMAL(12,2).
Floating pointDOUBLEDOUBLE PRECISIONFLOAT(53)BINARY_DOUBLEREALApproximate (IEEE 754). Never for money: 0.1 + 0.2 ≠ 0.3.
Single-precision floatFLOATREALREALBINARY_FLOATREALAbout 7 significant digits.
MoneyDECIMAL(19,4)NUMERIC(19,4)DECIMAL(19,4)NUMBER(19,4)INTEGER (cents)PostgreSQL MONEY and SQL Server MONEY exist but are locale- or precision-limited; prefer DECIMAL or integer cents.
BooleanBOOLEAN (TINYINT(1))BOOLEANBITBOOLEAN (23ai) / NUMBER(1)INTEGER 0/1Oracle added a SQL BOOLEAN type in 23ai.
Variable-length textVARCHAR(n)VARCHAR(n) / TEXTNVARCHAR(n)VARCHAR2(n)TEXTIn PostgreSQL VARCHAR(n) and TEXT perform the same; n is just a check.
Fixed-length textCHAR(n)CHAR(n)NCHAR(n)CHAR(n)TEXTPadded with spaces. Only for truly fixed codes (ISO country codes).
Long textTEXT / LONGTEXTTEXTNVARCHAR(MAX)CLOBTEXTMySQL TEXT holds 64 KB; MEDIUMTEXT 16 MB; LONGTEXT 4 GB.
Unicode textVARCHAR with utf8mb4TEXT (UTF-8 database)NVARCHARNVARCHAR2 or AL32UTF8 charsetTEXTIn MySQL use utf8mb4, not utf8 (which cannot store emoji).
EnumerationENUM('a','b')CREATE TYPE … AS ENUMVARCHAR + CHECKVARCHAR2 + CHECKTEXT + CHECKA lookup table with a foreign key is more flexible than an enum.
UUIDBINARY(16) / CHAR(36)UUIDUNIQUEIDENTIFIERRAW(16)TEXT / BLOBTime-ordered UUIDv7 indexes far better than random UUIDv4.
JSONJSONJSONBNVARCHAR(MAX) / JSON (2025)JSON (21c+)TEXT (json functions)PostgreSQL JSONB is binary, indexable with GIN; JSON keeps the raw text.
DateDATEDATEDATEDATETEXT (ISO 8601)Oracle DATE also stores a time of day to the second.
Time of dayTIMETIMETIMEINTERVAL DAY TO SECONDTEXT
Date and timeDATETIMETIMESTAMPDATETIME2TIMESTAMPTEXT (ISO 8601)No time zone stored.
Timestamp with time zoneTIMESTAMP (stored as UTC)TIMESTAMPTZDATETIMEOFFSETTIMESTAMP WITH TIME ZONETEXTBest default for “when did it happen”. MySQL TIMESTAMP ends in 2038.
Interval / duration(none, store seconds)INTERVAL(none, store seconds)INTERVALINTEGER
Binary dataBLOB / VARBINARY(n)BYTEAVARBINARY(MAX)BLOB / RAW(n)BLOBStore large files in object storage and keep the URL in the database.
Array(none, use JSON)INTEGER[] / TEXT[](none)VARRAY / nested table(none)Usually a child table is the relational answer.
SpatialGEOMETRY / POINTPOINT (PostGIS: geometry)GEOGRAPHY / GEOMETRYSDO_GEOMETRY(SpatiaLite)

Choosing a data type: five rules

  1. Pick the narrowest type that will always fit. Smaller types mean smaller indexes and more rows per page, but never so narrow that real data is truncated.
  2. Exact numbers for exact things. Money, quantities and percentages go in DECIMAL/NUMERIC or integers. Floats are for measurements.
  3. Store moments in UTC with a time zone-aware type and convert when displaying.
  4. Identifiers that look like numbers are text. Phone numbers, ZIP codes and card numbers have leading zeros and are never added together.
  5. Match foreign key types to the key they reference. A BIGINT key referenced by an INT column will fail or force implicit casts in joins.

The CSV to SQL converter applies these rules when it infers column types, and the DBML editor maps types when converting a schema between PostgreSQL, MySQL, SQL Server and SQLite. The type mappings above follow each vendor’s official documentation.

Questions

What are the main SQL data types?

Numeric (INTEGER, BIGINT, DECIMAL/NUMERIC, FLOAT), character (CHAR, VARCHAR, TEXT), date and time (DATE, TIME, TIMESTAMP), boolean, and binary (BLOB/BYTEA). Most databases add JSON, UUID, and spatial types.

What is the difference between VARCHAR and TEXT?

VARCHAR(n) caps the length at n characters; TEXT has no declared limit. In PostgreSQL they are stored and perform identically. In MySQL, TEXT columns are stored off-page, cannot have a default value before 8.0.13, and need a prefix length to be indexed, so VARCHAR is preferred for short strings.

Which data type should I use for money?

An exact type: DECIMAL(19,4) or NUMERIC(12,2), or an integer number of cents. Never FLOAT or DOUBLE, which store binary approximations and produce rounding errors such as 0.1 + 0.2 = 0.30000000000000004.

Should I store dates as timestamps with time zone?

For moments in time (created_at, paid_at), yes: TIMESTAMPTZ in PostgreSQL, DATETIMEOFFSET in SQL Server, or UTC in a DATETIME column in MySQL. For calendar dates without a time (a birthday), use DATE.

Why does SQLite accept any type?

SQLite uses dynamic typing with “type affinity”: a column’s declared type is a preference, not a rule, and values keep their own type. Since version 3.37 you can declare a table STRICT to enforce INTEGER, REAL, TEXT, BLOB or ANY.

INT or BIGINT for primary keys?

INT runs out at about 2.1 billion rows (or inserts, since failed inserts can consume ids). If a table could plausibly grow that large, such as events, logs or messages, use BIGINT from the start; changing a primary key type later means rewriting the table and every foreign key.

Related tools