PostgreSQL进阶

窗口函数

-- 排名函数 SELECT name, dept, salary, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rank, DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS dense_rank, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS row_num, NTILE(4) OVER (ORDER BY salary DESC) AS quartile FROM employees; -- 聚合作为窗口函数 SELECT name, salary, dept, SUM(salary) OVER (PARTITION BY dept) AS dept_total, AVG(salary) OVER (PARTITION BY dept) AS dept_avg, salary - AVG(salary) OVER (PARTITION BY dept) AS vs_avg FROM employees; -- 累计求和 / 移动平均 SELECT date, amount, SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative, AVG(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg_7d FROM sales; -- LAG / LEAD(访问相邻行) SELECT date, revenue, LAG(revenue, 1) OVER (ORDER BY date) AS prev_day, LEAD(revenue, 1) OVER (ORDER BY date) AS next_day, revenue - LAG(revenue, 1) OVER (ORDER BY date) AS day_change FROM daily_revenue;

JSONB 操作

-- 基本 JSONB 访问 SELECT data->>'name' AS name, -- 文本 data->'address' AS address, -- jsonb data#>>'{address,city}' AS city -- 嵌套文本 FROM users; -- JSONB 内查询 SELECT * FROM products WHERE data @> '{"category": "electronics"}'; -- 包含查询 SELECT * FROM products WHERE data ? 'discount'; -- key 存在 -- 修改 JSONB UPDATE users SET data = jsonb_set(data, '{address,zip}', '"100000"') WHERE id = 42; UPDATE users SET data = data || '{"verified": true}'; -- 合并 UPDATE users SET data = data - 'temp_token'; -- 删除 key -- JSONB 索引 CREATE INDEX idx_users_data ON users USING GIN(data); CREATE INDEX idx_users_email ON users ((data->>'email'));

全文搜索

-- 基本全文搜索 SELECT title, ts_rank(search_vec, query) AS rank FROM articles, to_tsquery('chinese', '数据库 & 优化') AS query WHERE search_vec @@ query ORDER BY rank DESC; -- 创建 tsvector 生成列(自动更新) ALTER TABLE articles ADD COLUMN search_vec tsvector GENERATED ALWAYS AS ( setweight(to_tsvector('chinese', coalesce(title,'')), 'A') || setweight(to_tsvector('chinese', coalesce(body,'')), 'B') ) STORED; CREATE INDEX idx_articles_fts ON articles USING GIN(search_vec); -- 高亮匹配结果 SELECT ts_headline('chinese', body, to_tsquery('性能'), 'StartSel=, StopSel=, MaxWords=30') AS snippet FROM articles;

CTE 与横向连接

-- CTE(公共表表达式) WITH monthly_totals AS ( SELECT DATE_TRUNC('month', created_at) AS month, SUM(amount) AS total FROM orders GROUP BY 1 ), ranked AS ( SELECT *, RANK() OVER (ORDER BY total DESC) AS rk FROM monthly_totals ) SELECT * FROM ranked WHERE rk <= 3; -- 递归 CTE(树形遍历) WITH RECURSIVE category_tree AS ( SELECT id, name, parent_id, 0 AS depth FROM categories WHERE parent_id IS NULL UNION ALL SELECT c.id, c.name, c.parent_id, t.depth + 1 FROM categories c JOIN category_tree t ON c.parent_id = t.id ) SELECT * FROM category_tree ORDER BY depth, name; -- LATERAL 连接(每用户取最新3篇) SELECT u.name, recent.title, recent.created_at FROM users u CROSS JOIN LATERAL ( SELECT title, created_at FROM posts WHERE user_id = u.id ORDER BY created_at DESC LIMIT 3 ) AS recent;