PostgreSQL 数据库的典型操作

以下是 PostgreSQL 数据库的典型操作分类及代码案例:

一、数据库管理操作

1. 数据库创建与连接

sql

复制代码
-- 创建数据库
CREATE DATABASE company_db 
WITH ENCODING='UTF8' 
OWNER=admin 
CONNECTION LIMIT 100;

-- 连接数据库
\c company_db;

-- 查看所有数据库
\l

-- 查看当前数据库
SELECT current_database();

2. 表空间管理

sql

复制代码
-- 创建表空间
CREATE TABLESPACE fast_space 
LOCATION '/var/lib/postgresql/data/fast';

-- 在表空间创建表
CREATE TABLE orders (
    id SERIAL,
    order_date DATE
) TABLESPACE fast_space;

二、表结构操作

1. 创建表

sql

复制代码
-- 基础表创建
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE,
    salary DECIMAL(10,2) CHECK (salary > 0),
    hire_date DATE DEFAULT CURRENT_DATE,
    department_id INTEGER,
    created_at TIMESTAMP DEFAULT NOW(),
    data JSONB
);

-- 创建分区表(PostgreSQL 13+)
CREATE TABLE sales (
    id SERIAL,
    sale_date DATE NOT NULL,
    amount DECIMAL(10,2)
) PARTITION BY RANGE (sale_date);

-- 创建子分区
CREATE TABLE sales_2023_q1 PARTITION OF sales
FOR VALUES FROM ('2023-01-01') TO ('2023-04-01');

2. 修改表结构

sql

复制代码
-- 添加列
ALTER TABLE employees ADD COLUMN phone VARCHAR(20);

-- 修改列类型
ALTER TABLE employees ALTER COLUMN phone TYPE VARCHAR(30);

-- 添加约束
ALTER TABLE employees 
ADD CONSTRAINT fk_department 
FOREIGN KEY (department_id) 
REFERENCES departments(id);

-- 创建索引
CREATE INDEX idx_employees_name ON employees(name);
CREATE INDEX idx_employees_department ON employees(department_id);
CREATE INDEX idx_employees_hire_date ON employees(hire_date DESC);

-- 添加部分索引
CREATE INDEX idx_high_salary ON employees(salary) 
WHERE salary > 100000;

-- 添加表达式索引
CREATE INDEX idx_lower_email ON employees(LOWER(email));

三、数据操作(CRUD)

1. 插入数据

sql

复制代码
-- 插入单行
INSERT INTO employees (name, email, salary, department_id) 
VALUES ('张三', 'zhangsan@company.com', 50000.00, 1);

-- 插入多行
INSERT INTO employees (name, email, salary) 
VALUES 
    ('李四', 'lisi@company.com', 45000.00),
    ('王五', 'wangwu@company.com', 60000.00),
    ('赵六', 'zhaoliu@company.com', 55000.00);

-- 插入并返回结果
INSERT INTO employees (name, email) 
VALUES ('孙七', 'sunqi@company.com') 
RETURNING id, name;

-- 插入JSON数据
INSERT INTO employees (name, data) 
VALUES ('钱八', '{"skills": ["Python", "PostgreSQL"], "level": "Senior"}');

2. 查询数据

sql

复制代码
-- 基础查询
SELECT * FROM employees;

-- 条件查询
SELECT name, salary 
FROM employees 
WHERE salary > 50000 
  AND hire_date > '2023-01-01';

-- 连接查询
SELECT e.name, d.department_name, e.salary
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
WHERE d.location = '上海';

-- 聚合查询
SELECT 
    department_id,
    COUNT(*) as employee_count,
    AVG(salary) as avg_salary,
    MAX(salary) as max_salary
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5
ORDER BY avg_salary DESC;

-- 窗口函数
SELECT 
    name,
    salary,
    department_id,
    RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) as salary_rank,
    AVG(salary) OVER (PARTITION BY department_id) as dept_avg_salary
FROM employees;

-- JSON查询
SELECT 
    name,
    data->>'level' as level,
    data->'skills' as skills
FROM employees
WHERE data @> '{"level": "Senior"}';

-- 递归查询(CTE)
WITH RECURSIVE employee_hierarchy 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, eh.level + 1
    FROM employees e
    INNER JOIN employee_hierarchy eh ON e.manager_id = eh.id
)
SELECT * FROM employee_hierarchy
ORDER BY level, name;

3. 更新数据

sql

复制代码
-- 普通更新
UPDATE employees 
SET salary = salary * 1.1 
WHERE hire_date < '2020-01-01';

-- 基于子查询更新
UPDATE employees e
SET salary = salary * 1.05
FROM departments d
WHERE e.department_id = d.id 
  AND d.department_name = '研发部';

-- 更新JSON字段
UPDATE employees
SET data = jsonb_set(data, '{skills}', '["Java", "PostgreSQL", "Redis"]')
WHERE id = 1;

-- 更新并返回结果
UPDATE employees 
SET salary = salary + 5000 
WHERE department_id = 2 
RETURNING id, name, salary;

4. 删除数据

sql

复制代码
-- 条件删除
DELETE FROM employees 
WHERE hire_date < '2018-01-01';

-- 关联删除
DELETE FROM employees e
USING departments d
WHERE e.department_id = d.id 
  AND d.department_name = '已解散部门';

-- 清空表(速度快,不可回滚)
TRUNCATE TABLE audit_log;

-- 删除并返回结果
DELETE FROM employees 
WHERE id = 100 
RETURNING *;

四、事务控制

sql

复制代码
-- 事务示例
BEGIN;

-- 检查账户余额
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;

-- 转账操作
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;

-- 记录流水
INSERT INTO transactions (from_account, to_account, amount) 
VALUES (1, 2, 1000);

-- 提交或回滚
COMMIT;
-- 或 ROLLBACK;

五、视图与物化视图

sql

复制代码
-- 创建视图
CREATE VIEW employee_summary AS
SELECT 
    d.department_name,
    COUNT(e.id) as employee_count,
    AVG(e.salary) as avg_salary
FROM employees e
JOIN departments d ON e.department_id = d.id
GROUP BY d.department_name;

-- 使用视图
SELECT * FROM employee_summary WHERE employee_count > 10;

-- 创建物化视图
CREATE MATERIALIZED VIEW monthly_sales_summary AS
SELECT 
    DATE_TRUNC('month', sale_date) as month,
    SUM(amount) as total_sales,
    COUNT(*) as transaction_count
FROM sales
GROUP BY DATE_TRUNC('month', sale_date);

-- 刷新物化视图
REFRESH MATERIALIZED VIEW monthly_sales_summary;

六、存储过程与函数

sql

复制代码
-- 创建函数
CREATE OR REPLACE FUNCTION get_employee_count(dept_id INT)
RETURNS INT AS $$
DECLARE
    emp_count INT;
BEGIN
    SELECT COUNT(*) INTO emp_count
    FROM employees
    WHERE department_id = dept_id;
    
    RETURN emp_count;
END;
$$ LANGUAGE plpgsql;

-- 调用函数
SELECT get_employee_count(1);

-- 创建带参数的函数
CREATE OR REPLACE FUNCTION update_salary(
    emp_id INT, 
    increase_percent DECIMAL
) RETURNS DECIMAL AS $$
DECLARE
    old_salary DECIMAL;
    new_salary DECIMAL;
BEGIN
    -- 获取当前工资
    SELECT salary INTO old_salary
    FROM employees
    WHERE id = emp_id;
    
    -- 计算新工资
    new_salary := old_salary * (1 + increase_percent/100);
    
    -- 更新工资
    UPDATE employees
    SET salary = new_salary
    WHERE id = emp_id;
    
    RETURN new_salary;
END;
$$ LANGUAGE plpgsql;

-- 调用带参数的函数
SELECT update_salary(1, 10);

七、触发器示例

sql

复制代码
-- 创建审计表
CREATE TABLE employee_audit (
    id SERIAL PRIMARY KEY,
    employee_id INT,
    changed_field VARCHAR(50),
    old_value TEXT,
    new_value TEXT,
    changed_at TIMESTAMP DEFAULT NOW(),
    changed_by VARCHAR(100)
);

-- 创建触发器函数
CREATE OR REPLACE FUNCTION log_employee_changes()
RETURNS TRIGGER AS $$
BEGIN
    IF (TG_OP = 'UPDATE') THEN
        IF OLD.salary != NEW.salary THEN
            INSERT INTO employee_audit (employee_id, changed_field, old_value, new_value)
            VALUES (OLD.id, 'salary', OLD.salary::TEXT, NEW.salary::TEXT);
        END IF;
        
        IF OLD.department_id != NEW.department_id THEN
            INSERT INTO employee_audit (employee_id, changed_field, old_value, new_value)
            VALUES (OLD.id, 'department_id', OLD.department_id::TEXT, NEW.department_id::TEXT);
        END IF;
        
    ELSIF (TG_OP = 'DELETE') THEN
        INSERT INTO employee_audit (employee_id, changed_field, old_value, new_value)
        VALUES (OLD.id, 'status', '在职', '离职');
        
    ELSIF (TG_OP = 'INSERT') THEN
        INSERT INTO employee_audit (employee_id, changed_field, old_value, new_value)
        VALUES (NEW.id, 'status', NULL, '新入职');
    END IF;
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 创建触发器
CREATE TRIGGER tr_employee_audit
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
EXECUTE FUNCTION log_employee_changes();

八、备份与恢复

sql

复制代码
-- 逻辑备份单个数据库
-- 在命令行执行,不是SQL
-- pg_dump -U username -d database_name -f backup.sql

-- 备份所有数据库
-- pg_dumpall -U username -f all_backup.sql

-- 备份特定表
-- pg_dump -U username -d database_name -t table_name -f table_backup.sql

-- 恢复数据库
-- psql -U username -d database_name -f backup.sql

-- 创建物理备份点
SELECT pg_start_backup('before_migration', true);
-- 执行文件系统备份...
SELECT pg_stop_backup();

九、性能监控与维护

sql

复制代码
-- 查看表大小
SELECT 
    schemaname,
    tablename,
    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as total_size,
    pg_size_pretty(pg_relation_size(schemaname||'.'||tablename)) as table_size,
    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename) - 
                   pg_relation_size(schemaname||'.'||tablename)) as index_size
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

-- 查看索引使用情况
SELECT 
    schemaname,
    tablename,
    indexname,
    idx_scan as index_scans,
    idx_tup_read as tuples_read,
    idx_tup_fetch as tuples_fetched
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;

-- 手动收集统计信息
ANALYZE employees;

-- 清理和优化表
VACUUM ANALYZE employees;

-- 重建索引
REINDEX INDEX idx_employees_name;

十、权限管理

sql

复制代码
-- 创建角色
CREATE ROLE analyst WITH LOGIN PASSWORD 'secure_password';
CREATE ROLE readonly WITH NOLOGIN;

-- 授予权限
GRANT CONNECT ON DATABASE company_db TO analyst;
GRANT USAGE ON SCHEMA public TO analyst;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
GRANT SELECT, INSERT, UPDATE ON employees TO analyst;

-- 创建只读用户
CREATE USER viewer WITH PASSWORD 'view_only';
GRANT readonly TO viewer;

-- 查看权限
\dp employees

这些操作覆盖了 PostgreSQL 日常使用中的典型场景。在实际使用中,建议结合具体业务需求进行调整和优化。对于生产环境的重要操作,请务必先在测试环境验证,并做好备份。

相关推荐
正在走向自律2 小时前
AiOnly平台x FastGPT:一键调用Gemini 3 Pro系列模型从零构建AI工作流
大数据·数据库·人工智能·aionly·nano banana pro·gemini 3 pro
仰泳的熊猫2 小时前
1140 Look-and-say Sequence
数据结构·c++·算法·pat考试
EXtreme352 小时前
栈与队列的“跨界”对话:如何用双队列完美模拟栈的LIFO特性?
c语言·数据结构·leetcode·双队列模拟栈·算法思维
松涛和鸣3 小时前
29、Linux进程核心概念与编程实战:fork/getpid全解析
linux·运维·服务器·网络·数据结构·哈希算法
ao_lang3 小时前
MySQL的存储过程和触发器
android·数据库·mysql
hweiyu003 小时前
数据结构:有向图
数据结构
呱呱巨基3 小时前
C++ 红黑树
数据结构·c++·笔记·学习
JIngJaneIL3 小时前
基于Java酒店管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
颜颜yan_3 小时前
DevUI自定义开发实践:从零开始构建自定义组件和插件
android·java·数据库