CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(64) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password CHAR(64) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
role VARCHAR(32) NOT NULL DEFAULT 'user',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
author_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(200) NOT NULL,
slug VARCHAR(200) NOT NULL UNIQUE,
body TEXT NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'draft'
CHECK (status IN ('draft', 'published', 'archived')),
view_count INTEGER NOT NULL DEFAULT 0,
published_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
SELECT
u.username,
u.email,
p.title,
p.status,
p.view_count
FROM users u
JOIN posts p ON p.author_id = u.id
WHERE u.is_active = TRUE
AND p.status != 'archived'
ORDER BY p.created_at DESC
LIMIT 20;
WITH cte AS (
SELECT author_id, COUNT(*) AS cnt
FROM posts
GROUP BY author_id
)
SELECT u.username, cte.cnt
FROM users u
JOIN cte ON cte.author_id = u.id;
UPDATE posts
SET status = 'archived',
updated_at = CURRENT_TIMESTAMP
WHERE published_at < datetime('now', '-1 year')
AND status = 'published';
SELECT
NULL AS maybe_value,
COALESCE(u.email, 'no-email') AS safe_email,
CASE
WHEN p.view_count > 1000 THEN 'popular'
WHEN p.view_count > 100 THEN 'moderate'
ELSE 'quiet'
END AS popularity
FROM users u
LEFT JOIN posts p ON p.author_id = u.id;