Working with Data Types

1. Using Integer Types

TypeSizeRange
smallint2 B-32,768 to 32,767
integer / int4 B±2.1B
bigint8 B±9.2 quintillion

2. Using Numeric Types

TypeUse
numeric(p,s)Exact, arbitrary precision (money, scientific)
real4-byte float
double precision8-byte float
moneyLocale-aware (avoid; use numeric)
CREATE TABLE prices (amount numeric(12,2) NOT NULL);

3. Using Serial Types

TypeUnderlyingStatus
smallserialsmallint + sequenceLEGACY
serialinteger + sequenceLEGACY
bigserialbigint + sequenceLEGACY
Note: Prefer GENERATED ALWAYS AS IDENTITY — SQL-standard and avoids permission quirks.

4. Using Character Types

TypeNotes
textUnlimited length (preferred)
varchar(n)Max n chars; no perf benefit vs text
char(n)Blank-padded fixed (avoid)
citextCase-insensitive (extension)

5. Using Boolean Type

LiteralMaps To
TRUE't', 'true', 'yes', 'on', '1'
FALSE'f', 'false', 'no', 'off', '0'
NULLunknown

6. Using Date and Time Types

TypeSizeNotes
date4 BCalendar day
time [(p)]8 BTime of day, no TZ
timetz12 BAvoid; no DST awareness
timestamp8 BWithout timezone
timestamptz8 BStored UTC; recommended

7. Using INTERVAL Type

SELECT INTERVAL '1 year 2 months 3 days 04:05:06';
SELECT now() + INTERVAL '30 days';
SELECT EXTRACT(EPOCH FROM INTERVAL '1 day');  -- 86400
FieldExample
MonthsINTERVAL '3 months'
DaysINTERVAL '7 days'
MicrosecondsINTERVAL '0.5 seconds'

8. Using UUID Type

CREATE EXTENSION IF NOT EXISTS pgcrypto;
SELECT gen_random_uuid();              -- v4
-- PG 18+ has gen_uuid_v7() for time-ordered UUIDs
SourceFunction
pgcryptogen_random_uuid()
uuid-osspuuid_generate_v1mc(), uuid_generate_v4()

9. Using JSON Types

TypeStorageUse
jsonVerbatim textPreserve formatting; rarely needed
jsonbBinary, indexedDefault choice
CREATE TABLE events (
  id bigserial PRIMARY KEY,
  payload jsonb NOT NULL
);
CREATE INDEX events_payload_gin ON events USING gin (payload jsonb_path_ops);

10. Using Array Types

CREATE TABLE posts (
    id   bigserial PRIMARY KEY,
    tags text[] NOT NULL DEFAULT '{}'
);
INSERT INTO posts(tags) VALUES (ARRAY['sql','postgres','tips']);
SELECT * FROM posts WHERE 'sql' = ANY(tags);
CREATE INDEX posts_tags_gin ON posts USING gin(tags);

11. Using ENUM Types

CREATE TYPE order_status AS ENUM ('new','paid','shipped','cancelled');
ALTER TABLE orders ALTER COLUMN status TYPE order_status USING status::order_status;
ALTER TYPE order_status ADD VALUE 'refunded' AFTER 'cancelled';
OpNotes
ADD VALUECannot run inside transaction block before PG 12
Sort orderDefinition order, not alphabetical
RenameALTER TYPE ... RENAME VALUE 'a' TO 'b'

12. Using Composite Types

CREATE TYPE address AS (street text, city text, zip text);
CREATE TABLE people (id bigserial PRIMARY KEY, home address);
INSERT INTO people(home) VALUES (ROW('1 Main','Boston','02110'));
SELECT (home).city FROM people;

13. Using Domain Types

CREATE DOMAIN email_addr AS text
  CHECK (VALUE ~* '^[^@]+@[^@]+\.[^@]+
      
BenefitDetail
ReuseApply same CHECK to many columns
CentralizeChange rule in one place

14. Using Range Types

TypeElement
int4range / int8rangeinteger / bigint
numrangenumeric
tsrange / tstzrangetimestamp / timestamptz
daterangedate
CREATE TABLE reservations (
   room_id int NOT NULL,
   during  tstzrange NOT NULL,
   EXCLUDE USING gist (room_id WITH =, during WITH &&)
);

15. Using Network Types

TypeUse
inetHost or network IPv4/IPv6 with optional CIDR
cidrStrict network (no host bits)
macaddr6-byte MAC address
macaddr88-byte EUI-64 MAC
SELECT '192.168.1.10'::inet << '192.168.1.0/24'::cidr;   -- true
);
CREATE TABLE users (id bigserial PRIMARY KEY, email email_addr NOT NULL);
BenefitDetail
ReuseApply same CHECK to many columns
CentralizeChange rule in one place

14. Using Range Types

TypeElement
int4range / int8rangeinteger / bigint
numrangenumeric
tsrange / tstzrangetimestamp / timestamptz
daterangedate
CREATE TABLE reservations (
   room_id int NOT NULL,
   during  tstzrange NOT NULL,
   EXCLUDE USING gist (room_id WITH =, during WITH &&)
);

15. Using Network Types

TypeUse
inetHost or network IPv4/IPv6 with optional CIDR
cidrStrict network (no host bits)
macaddr6-byte MAC address
macaddr88-byte EUI-64 MAC
SELECT '192.168.1.10'::inet << '192.168.1.0/24'::cidr;   -- true