Q1Which of the following is a correct benefit of storing dates as ISO strings like '2024-03-15'?
Date/Time Types and STRICT Tables
Using the 50,000-row perf_sales table, learn the three date storage formats (ISO strings, julianday, unixepoch), year-based and range aggregation with date() / strftime(), and how the typed_strict table rejects type mismatches — all run live in the browser.
The data we'll use — perf_sales
Dates are stored as either strings or numbers, and you read or compute them with functions like date() / strftime().
In the first half, you'll use the sale_date column of the perf_sales sales table to check the three storage formats and how to extract values; in the second half, you'll create a STRICT table yourself to see what happens when you insert a value that doesn't match the declared type.
The three date storage formats — ISO string / julianday / unixepoch
Dates and times can be stored in three main formats.
| Format | Example value | Main use |
|---|---|---|
| ISO string | '2024-03-15' (with time: '2024-03-15 12:30:00') | Human-readable; sorting and range comparison work correctly as plain string comparison (the most common choice) |
| julianday | julianday('2024-03-15') → 2460384.5 (a decimal counting days since antiquity) | Computing the difference between two dates in days |
| unixepoch | strftime('%s', ...) → 1710460800 (integer seconds since 1970-01-01) | Second-level time math / interoperating between systems |
Whichever format you store, you can read it back as 'YYYY-MM-DD' with date() or as 'YYYY-MM-DD HH:MM:SS' with datetime().
This course uses the ISO string by default because it's human-readable and easy to compare, and only converts to julianday / unixepoch when needed.
-- The same date in 3 formats (read-only example)
SELECT '2024-03-15' AS iso_text,
julianday('2024-03-15') AS as_julianday,
strftime('%s','2024-03-15 00:00:00') AS as_unixepoch;
-- Convert each of the 3 formats back to a readable date
SELECT date(julianday('2024-03-15')) AS from_jd,
datetime(1710460800,'unixepoch') AS from_unix,
date('2024-03-15') AS from_iso;
-- With ISO strings, range comparison works correctly as plain string comparison
SELECT '2024-03-15' BETWEEN '2024-01-01' AND '2024-12-31' AS in_2024; -- 1
Manipulate and aggregate dates with date() and strftime()
date(value, modifier...): returns the date part as'YYYY-MM-DD', and lets you do date math with modifiers like'+1 month'/'-7 days'/'start of month'strftime(format, value): extracts a piece of the date as a string using format specifiers like%Y(year),%m(month),%d(day),%w(day of week)- Combine
strftime('%Y', sale_date)withGROUP BYto aggregate by year - Because
sale_dateis stored as an ISO string, range conditions like `WHERE sale_date >= '2024-01-01'` work correctly as plain string comparisons
-- Date manipulation (read-only example)
SELECT date('2024-03-15','+1 month') AS plus_1_month, -- 2024-04-15
date('2024-03-15','start of month') AS month_start, -- 2024-03-01
strftime('%Y', '2024-03-15') AS year_part, -- 2024
strftime('%Y-%m','2024-03-15') AS year_month; -- 2024-03
-- Count by year (ISO string, so extract the year with strftime and GROUP BY)
SELECT strftime('%Y', sale_date) AS yr, COUNT(*) AS cnt
FROM perf_sales
GROUP BY yr
ORDER BY yr;
STRICT tables — enforce strict typing
The type affinity we've seen so far flexibly converts numeric-looking strings.
By contrast, when you add STRICT at the end of a table definition, that table rejects storing values whose type doesn't match the declared one.
If you try to insert a non-numeric string into a numeric column, the value isn't converted implicitly — you get an error.
Use this for tables where you want to catch type mix-ups early.
In a STRICT table, the allowed column types are limited to INTEGER / REAL / TEXT / BLOB / ANY — INT and custom type names aren't allowed.
In the next exercise you'll create a typed_strict table with STRICT yourself, and in the following exercises you'll insert both matching and mismatched values to see the difference.
-- Declaring and using a STRICT table (read-only example)
CREATE TABLE IF NOT EXISTS typed_strict(a INTEGER, b TEXT, c REAL) STRICT;
-- Rows with matching types insert just fine
INSERT INTO typed_strict VALUES (1, '2024-03-15', 1.5);
-- Inserting a non-numeric string into the a INTEGER column
-- is not implicitly converted -- the INSERT errors out:
-- cannot store TEXT value in INTEGER column typed_strict.a
INSERT INTO typed_strict VALUES ('not-a-number', 'x', 1.0);
Knowledge Check
Answer each question one by one.
Q2Which of the following correctly describes the role of strftime('%Y', sale_date)?
Q3Which of the following correctly describes what happens when you try to INSERT a non-numeric string into an INTEGER column of a STRICT table?