๐Ÿ“ Quiz: Part II โ€” SQL (Chapters 5-8)

1. What does LEFT JOIN return when there's no match in the right table?

2. What's the difference between WHERE and HAVING?

3. What does a window function do differently from GROUP BY?

4. Why is OFFSET 1000000 problematic for pagination?

5. What is a CTE (WITH clause) primarily used for?


Chapter 9: Data Types โ€” Choosing the Right One

Choosing the right data type affects storage size, query performance, data integrity, and what operations you can perform. Get it wrong and you'll pay for it forever (migrations are painful).

Numeric Types

TypeSizeRangeUse When
SMALLINT2 bytes-32,768 to 32,767Status codes, small counters
INTEGER4 bytes-2.1B to 2.1BMost IDs, counts, general use
BIGINT8 bytes-9.2ร—10ยนโธ to 9.2ร—10ยนโธLarge IDs, timestamps as int
NUMERIC(p,s)VariableExact, user-defined precisionMoney, financial calculations
REAL4 bytes~6 decimal digits precisionScientific data (approx OK)
DOUBLE PRECISION8 bytes~15 decimal digits precisionScientific data (approx OK)
SERIAL4 bytesAuto-increment INTEGERPrimary keys
BIGSERIAL8 bytesAuto-increment BIGINTHigh-volume PKs
โš ๏ธ Never Use FLOAT for Money

0.1 + 0.2 = 0.30000000000000004 in floating point. Use NUMERIC(10,2) for money, or store cents as INTEGER (e.g., $19.99 โ†’ 1999).

String Types

TypeBehaviorUse When
CHAR(n)Fixed-length, padded with spacesFixed-format codes (ISO country: CHAR(2))
VARCHAR(n)Variable-length, max n charsMost strings with known max length
TEXTVariable-length, unlimitedLong text, no length constraint needed
๐Ÿ’ก PostgreSQL Tip

In PostgreSQL, VARCHAR(n) and TEXT have identical performance. The only difference is the length check. If you don't have a natural max length, just use TEXT. Add a CHECK constraint if you need validation.

Date/Time Types

TypeStoresExample
DATEDate only2024-03-15
TIMETime only14:30:00
TIMESTAMPDate + time (no timezone)2024-03-15 14:30:00
TIMESTAMPTZDate + time + timezone2024-03-15 14:30:00+02
INTERVALDuration3 days 04:05:06
โš ๏ธ Always Use TIMESTAMPTZ

Use TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) for any point-in-time data. Plain TIMESTAMP doesn't store timezone info โ€” if your servers are in different timezones, you'll get wrong results. TIMESTAMPTZ stores everything in UTC internally and converts on display.

Boolean

-- BOOLEAN: true, false, or NULL
CREATE TABLE features (
    name    TEXT,
    enabled BOOLEAN NOT NULL DEFAULT false
);

SELECT * FROM features WHERE enabled;  -- shorthand for = true

UUID

-- UUID: 128-bit universally unique identifier
-- Example: 550e8400-e29b-41d4-a716-446655440000

CREATE TABLE sessions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id INTEGER NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);
๐Ÿ’ก UUID vs SERIAL for Primary Keys

JSON/JSONB (PostgreSQL)

-- JSONB: binary JSON, indexable, queryable
CREATE TABLE events (
    id   SERIAL PRIMARY KEY,
    data JSONB NOT NULL
);

INSERT INTO events (data) VALUES
    ('{"type": "login", "user": "alice", "ip": "1.2.3.4"}');

-- Query JSON fields
SELECT data->'user' FROM events WHERE data->>'type' = 'login';

Arrays (PostgreSQL)

CREATE TABLE posts (
    id   SERIAL PRIMARY KEY,
    tags TEXT[]
);

INSERT INTO posts (tags) VALUES ('{grpc, protobuf, networking}');

-- Find posts with a specific tag
SELECT * FROM posts WHERE 'grpc' = ANY(tags);

Quick Decision Guide

DataUseDon't Use
MoneyNUMERIC(12,2) or INTEGER (cents)FLOAT, DOUBLE
IDs (single system)SERIAL / BIGSERIALVARCHAR
IDs (distributed)UUIDSERIAL
TimestampsTIMESTAMPTZTIMESTAMP, VARCHAR, INTEGER
Yes/NoBOOLEANINTEGER, CHAR(1)
Short stringsVARCHAR(n) or TEXTCHAR(n) unless truly fixed
Semi-structuredJSONBTEXT (then parsing in app)
Key Takeaways