高级查询

返回 PostgreSQL

基础 SELECT基础命令;窗口函数可对照 MySQL 开窗函数


CTE(公共表表达式)

WITH recent_orders AS (
    SELECT user_id, COUNT(*) AS order_count
    FROM orders
    WHERE created_at > NOW() - INTERVAL '30 days'
    GROUP BY user_id
)
SELECT u.name, ro.order_count
FROM users u
JOIN recent_orders ro ON u.id = ro.user_id
WHERE ro.order_count > 5;

递归 CTE

WITH RECURSIVE org_tree AS (
    SELECT id, name, manager_id, 1 AS level
    FROM employees
    WHERE manager_id IS NULL
 
    UNION ALL
 
    SELECT e.id, e.name, e.manager_id, ot.level + 1
    FROM employees e
    JOIN org_tree ot ON e.manager_id = ot.id
)
SELECT * FROM org_tree ORDER BY level, name;

窗口函数

SELECT
    name,
    department,
    salary,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank,
    SUM(salary) OVER (PARTITION BY department) AS dept_total
FROM employees;
 
SELECT
    date,
    amount,
    SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative
FROM daily_sales;

全文搜索

CREATE INDEX idx_articles_tsv ON articles
    USING GIN(to_tsvector('english', title || ' ' || content));
 
SELECT title, ts_rank(to_tsvector('english', title || ' ' || content), query) AS rank
FROM articles, to_tsquery('english', 'postgresql & index') query
WHERE to_tsvector('english', title || ' ' || content) @@ query
ORDER BY rank DESC;

专业搜索场景见 Elasticsearch


分区表

CREATE TABLE orders (
    id         BIGINT,
    created_at TIMESTAMPTZ,
    amount     NUMERIC
) PARTITION BY RANGE (created_at);
 
CREATE TABLE orders_2023 PARTITION OF orders
    FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
 
CREATE TABLE orders_2024 PARTITION OF orders
    FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
 
CREATE TABLE user_logs (
    user_id BIGINT,
    action  TEXT
) PARTITION BY HASH (user_id);
 
CREATE TABLE user_logs_0 PARTITION OF user_logs FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE user_logs_1 PARTITION OF user_logs FOR VALUES WITH (MODULUS 4, REMAINDER 1);

相关