PostgreSQL 入门学习教程,从入门到精通,PostgreSQL 16 (Windows) 安装与核心语法实战指南(2)

PostgreSQL 16 (Windows) 安装与核心语法实战指南

本指南基于 PostgreSQL 16 版本,专为 Windows 环境设计。内容涵盖从下载安装到核心 SQL 语法、高级特性及综合案例的全流程解析。


第一部分:Windows 环境下安装 PostgreSQL 16

1.1 下载准备

  1. 访问 PostgreSQL 官方下载页面:https://www.postgresql.org/download/windows/
  2. 点击 "Download the installer" (通常由 EnterpriseDB 提供)。
  3. 选择 PostgreSQL 16 版本,下载对应的 Windows x86-64 安装包(例如 postgresql-16.x-windows-x64.exe)。

1.2 安装步骤详解

双击运行下载的安装包,按以下步骤操作:

  1. Welcome : 点击 Next
  2. Installation Directory : 选择安装路径(建议默认 C:\Program Files\PostgreSQL\16),点击 Next
  3. Select Components :
    • PostgreSQL Server: 数据库核心(必选)。
    • pgAdmin 4: 图形化管理工具(必选,方便新手)。
    • Command Line Tools : 命令行工具(必选,用于 psql)。
    • Stack Builder: 额外驱动和工具(可选,初学者可不选)。
    • 点击 Next
  4. Data Directory : 选择数据存放路径(默认即可),点击 Next
  5. Password : 关键步骤 。设置超级用户 postgres 的密码。
    • 注意:请务必牢记此密码,后续所有连接都需要用到。
    • 点击 Next
  6. Port : 默认端口为 5432。如果本机已安装其他数据库占用此端口,可修改为 5433 等。点击 Next
  7. Locale : 保持默认 Default locale (通常对应系统语言),点击 Next
  8. Pre-installation Summary : 确认信息,点击 Next 开始安装。
  9. Installation Complete : 安装完成后,取消勾选 "Stack Builder"(如果不需要),点击 Finish

1.3 环境变量配置 (重要)

为了在 CMD 或 PowerShell 的任何目录下使用 psql 命令,需配置环境变量:

  1. 右键"此电脑" -> "属性" -> "高级系统设置" -> "环境变量"。

  2. 系统变量 中找到 Path,点击"编辑"。

  3. 点击"新建",添加 PostgreSQL 的 bin 目录路径,例如:
    C:\Program Files\PostgreSQL\16\bin

  4. 连续点击"确定"保存。

  5. 验证安装 :打开新的 CMD 窗口,输入:

    cmd 复制代码
    psql --version

    若显示 psql (PostgreSQL) 16.x,则安装成功。

1.4 首次连接测试

打开 CMD,输入以下命令连接数据库:

cmd 复制代码
psql -U postgres
  • 输入安装时设置的密码(输入时不会显示字符,直接回车即可)。
  • 看到 postgres=# 提示符即表示连接成功。

第二部分:核心语法知识点与案例代码

PostgreSQL 遵循标准 SQL,但拥有许多强大的扩展特性。以下知识点均包含详细注释的代码案例。

2.1 数据库与模式管理 (DDL)

知识点

  • CREATE DATABASE: 创建数据库。
  • SCHEMA: 逻辑命名空间,用于隔离对象。
  • DROP: 删除对象。

案例代码

sql 复制代码
-- 1. 创建一个新的数据库名为 'shop_db'
-- 注意:创建数据库必须在 postgres 库下执行,不能在自己连接的库中创建自己
CREATE DATABASE shop_db;

-- 连接到新数据库 (在 psql 命令行中使用 \c 命令,SQL 脚本中通常由客户端处理)
-- \c shop_db 

-- 2. 在当前数据库中创建一个名为 'sales' 的模式 (Schema)
-- 模式类似于文件夹,用于分类管理表
CREATE SCHEMA sales;

-- 3. 创建一个名为 'dev' 的模式
CREATE SCHEMA dev;

-- 4. 查看当前所有模式
-- \dn (这是 psql 元命令,非标准 SQL)
SELECT schema_name FROM information_schema.schemata;

-- 5. 删除模式 (如果存在且为空)
DROP SCHEMA IF EXISTS dev;

2.2 数据类型与表创建 (Advanced DDL)

知识点

  • 丰富类型 : SERIAL (自增), JSONB (高效 JSON), ARRAY (数组), TIMESTAMPTZ (带时区时间)。
  • 约束 : PRIMARY KEY, FOREIGN KEY, CHECK, NOT NULL, UNIQUE.
  • 默认值 : DEFAULT.

案例代码

sql 复制代码
-- 切换到 sales 模式 (可选,为了方便演示)
SET search_path TO sales;

-- 创建 'users' 表
CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,              -- 自增主键,PG 特有语法
    username VARCHAR(50) NOT NULL UNIQUE,    -- 唯一且非空
    email VARCHAR(100) NOT NULL,
    is_active BOOLEAN DEFAULT TRUE,          -- 布尔类型,默认真
    created_at TIMESTAMPTZ DEFAULT NOW(),    -- 带时区的时间戳,默认为当前时间
    profile_data JSONB                       -- 存储灵活的 JSON 数据 (如偏好设置)
);

-- 创建 'products' 表
CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    price NUMERIC(10, 2) NOT NULL CHECK (price >= 0), -- 检查约束:价格必须>=0
    tags TEXT[],                                    -- 数组类型,存储标签
    stock_quantity INT DEFAULT 0
);

-- 创建 'orders' 表 (包含外键)
CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    order_date TIMESTAMPTZ DEFAULT NOW(),
    total_amount NUMERIC(10, 2),
    -- 外键约束:引用 users 表的 user_id,删除用户时级联删除订单
    CONSTRAINT fk_user FOREIGN KEY (user_id) 
        REFERENCES users(user_id) ON DELETE CASCADE
);

-- 插入测试数据 (演示特殊类型用法)
INSERT INTO users (username, email, profile_data) 
VALUES 
('alice', 'alice@example.com', '{"theme": "dark", "notifications": true}'::jsonb),
('bob', 'bob@example.com', '{"theme": "light", "lang": "zh-CN"}'::jsonb);

INSERT INTO products (name, price, tags, stock_quantity) 
VALUES 
('机械键盘', 599.00, ARRAY['电子', '办公', '热销'], 50),
('无线鼠标', 129.50, ARRAY['电子', '办公'], 120);

2.3 数据查询与操作 (DML & DQL)

知识点

  • CRUD : INSERT, SELECT, UPDATE, DELETE.
  • RETURNING 子句: PG 特色,插入/更新/删除后直接返回受影响的数据,无需二次查询。
  • JSONB 查询 : 使用 ->, ->>, @> 操作符。
  • 数组查询 : 使用 ANY, ALL, @>

案例代码

sql 复制代码
-- 1. 基础查询与排序
SELECT username, email, created_at 
FROM users 
WHERE is_active = TRUE 
ORDER BY created_at DESC;

-- 2. 使用 RETURNING 子句 (插入并立即获取生成的 ID)
-- 传统做法需要插入后查 LASTVAL(),PG 可以直接返回
INSERT INTO orders (user_id, total_amount) 
VALUES (1, 728.50) 
RETURNING order_id, order_date; 

-- 3. 更新操作 (带条件)
UPDATE products 
SET stock_quantity = stock_quantity - 1 
WHERE product_id = 1 
RETURNING name, stock_quantity; -- 返回更新后的库存

-- 4. JSONB 高级查询
-- 查询 profile_data 中 theme 为 'dark' 的用户
-- ->> 获取文本值,-> 获取 JSON 对象
SELECT username 
FROM users 
WHERE profile_data->>'theme' = 'dark';

-- 5. 数组查询
-- 查询 tags 包含 '热销' 的产品
-- @> 表示左边数组包含右边数组
SELECT name, tags 
FROM products 
WHERE tags @> ARRAY['热销'];

-- 6. 模糊查询与正则
-- 查询邮箱以 example 开头的用户
SELECT * FROM users WHERE email LIKE '%example%';
-- 正则匹配 (PG 强大之处)
SELECT * FROM users WHERE email ~ '^[a-z]+@example\.com$';

2.4 聚合函数与分组

知识点

  • 标准聚合: COUNT, SUM, AVG, MAX, MIN.
  • GROUP BYHAVING.
  • STRING_AGG: PG 特有的字符串聚合函数。

案例代码

sql 复制代码
-- 1. 统计每个用户的订单总数和总金额
SELECT 
    u.username, 
    COUNT(o.order_id) as order_count, 
    SUM(o.total_amount) as total_spent
FROM users u
JOIN orders o ON u.user_id = o.user_id
GROUP BY u.username
HAVING SUM(o.total_amount) > 100; -- 只筛选总消费大于 100 的用户

-- 2. 字符串聚合 (将产品的标签合并成一个字符串)
SELECT 
    name, 
    STRING_AGG(tag, ', ') as all_tags -- 假设 tags 已被展开,此处演示概念
FROM (
    SELECT name, UNNEST(tags) as tag FROM products
) sub
GROUP BY name;

2.5 视图与索引

知识点

  • VIEW: 虚拟表,简化复杂查询。
  • MATERIALIZED VIEW: 物化视图,物理存储结果,查询快但需刷新。
  • INDEX: 加速查询,PG 支持 B-Tree, Hash, GiST, GIN (针对 JSON/数组) 等。

案例代码

sql 复制代码
-- 1. 创建普通视图 (简化多表连接)
CREATE VIEW user_order_summary AS
SELECT 
    u.username, 
    u.email,
    COUNT(o.order_id) as order_count
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.username, u.email;

-- 查询视图
SELECT * FROM user_order_summary WHERE order_count > 0;

-- 2. 创建索引
-- 为经常查询的 email 字段创建 B-Tree 索引
CREATE INDEX idx_users_email ON users(email);

-- 为 JSONB 字段创建 GIN 索引 (加速 JSON 内部键值查询)
CREATE INDEX idx_users_profile ON users USING GIN (profile_data);

-- 为数组字段创建 GIN 索引 (加速数组包含查询)
CREATE INDEX idx_products_tags ON products USING GIN (tags);

2.6 事务控制 (Transaction)

知识点

  • BEGIN, COMMIT, ROLLBACK.
  • ACID 特性保证数据一致性。

案例代码

sql 复制代码
-- 模拟一个转账或库存扣减的事务
BEGIN;

-- 1. 扣减库存
UPDATE products SET stock_quantity = stock_quantity - 1 WHERE product_id = 1;

-- 2. 记录订单
INSERT INTO orders (user_id, total_amount) VALUES (1, 599.00);

-- 检查中间状态 (可选)
-- 如果发现库存不足或其他错误,执行 ROLLBACK;
-- 这里假设一切正常
COMMIT; 

-- 如果发生错误,回滚所有操作:
-- ROLLBACK;

第三部分:综合性实战案例

场景:电商实时库存与用户行为分析系统

需求

  1. 设计包含用户、商品、订单、订单详情的完整 schema。
  2. 实现一个功能:当用户下单时,自动扣减库存,如果库存不足则失败(使用触发器或应用层逻辑,此处演示触发器自动处理)。
  3. 创建一个物化视图,每日统计各分类的销售排行,并提供刷新机制。
  4. 利用 JSONB 存储商品的动态属性(如颜色、尺寸),并进行灵活查询。
3.1 完整初始化脚本
sql 复制代码
-- 清理旧环境 (谨慎生产环境使用)
DROP TABLE IF EXISTS order_items CASCADE;
DROP TABLE IF EXISTS orders CASCADE;
DROP TABLE IF EXISTS products CASCADE;
DROP TABLE IF EXISTS users CASCADE;
DROP MATERIALIZED VIEW IF EXISTS daily_sales_report CASCADE;

-- 1. 创建基础表
CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    reg_date TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    category VARCHAR(50),
    price NUMERIC(10, 2) NOT NULL,
    stock INT NOT NULL DEFAULT 0,
    attributes JSONB -- 存储动态属性,如 {"color": "red", "size": "L"}
);

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    user_id INT REFERENCES users(user_id),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    status VARCHAR(20) DEFAULT 'PENDING' -- PENDING, COMPLETED, CANCELLED
);

CREATE TABLE order_items (
    item_id SERIAL PRIMARY KEY,
    order_id INT REFERENCES orders(order_id) ON DELETE CASCADE,
    product_id INT REFERENCES products(product_id),
    quantity INT NOT NULL,
    price_at_purchase NUMERIC(10, 2) NOT NULL -- 记录购买时的单价
);

-- 2. 插入初始数据
INSERT INTO users (username) VALUES ('Charlie'), ('Diana');

INSERT INTO products (name, category, price, stock, attributes) VALUES 
('T-Shirt Red', 'Clothing', 29.99, 100, '{"color": "Red", "size": "M"}'::jsonb),
('T-Shirt Blue', 'Clothing', 29.99, 50, '{"color": "Blue", "size": "L"}'::jsonb),
('Coffee Mug', 'Home', 9.99, 200, '{"material": "Ceramic"}'::jsonb);

-- 3. 创建自动扣减库存的触发器函数
CREATE OR REPLACE FUNCTION decrease_stock() RETURNS TRIGGER AS $$
BEGIN
    -- 检查库存是否充足
    IF (SELECT stock FROM products WHERE product_id = NEW.product_id) < NEW.quantity THEN
        RAISE EXCEPTION '库存不足!产品 ID: %, 请求数量:%, 当前库存:%', 
            NEW.product_id, NEW.quantity, (SELECT stock FROM products WHERE product_id = NEW.product_id);
    END IF;

    -- 扣减库存
    UPDATE products 
    SET stock = stock - NEW.quantity 
    WHERE product_id = NEW.product_id;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 绑定触发器:在插入 order_items 之前执行
CREATE TRIGGER trg_decrease_stock
BEFORE INSERT ON order_items
FOR EACH ROW EXECUTE FUNCTION decrease_stock();

-- 4. 创建物化视图:每日销售统计
CREATE MATERIALIZED VIEW daily_sales_report AS
SELECT 
    DATE(o.created_at) as sale_date,
    p.category,
    COUNT(oi.item_id) as items_sold,
    SUM(oi.quantity * oi.price_at_purchase) as total_revenue
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
WHERE o.status = 'COMPLETED' -- 仅统计已完成的订单
GROUP BY DATE(o.created_at), p.category
ORDER BY sale_date DESC, total_revenue DESC;

-- 为物化视图创建唯一索引 (以便并发刷新)
CREATE UNIQUE INDEX idx_daily_sales_date_cat ON daily_sales_report(sale_date, category);
3.2 业务操作演示
sql 复制代码
-- === 场景 A: 正常下单 ===
BEGIN;
-- 1. 创建订单
INSERT INTO orders (user_id, status) VALUES (1, 'PENDING') RETURNING order_id;
-- 假设返回 order_id = 1

-- 2. 添加订单项 (触发器会自动扣减库存)
INSERT INTO order_items (order_id, product_id, quantity, price_at_purchase)
VALUES (1, 1, 2, 29.99); -- 买2件红色T恤

-- 3. 更新订单状态为完成
UPDATE orders SET status = 'COMPLETED' WHERE order_id = 1;
COMMIT;

-- 验证库存是否减少
SELECT name, stock FROM products WHERE product_id = 1; 
-- 预期:stock 从 100 变为 98

-- === 场景 B: 库存不足测试 ===
BEGIN;
INSERT INTO orders (user_id, status) VALUES (2, 'PENDING') RETURNING order_id;
-- 假设返回 order_id = 2

-- 尝试购买 1000 件 (远超库存)
INSERT INTO order_items (order_id, product_id, quantity, price_at_purchase)
VALUES (2, 1, 1000, 29.99); 
-- 预期报错:ERROR: 库存不足!...
ROLLBACK; -- 事务回滚,数据不变

-- === 场景 C: 复杂查询 (JSONB + 物化视图) ===

-- 1. 查询所有 "Red" 颜色的商品 (利用 JSONB)
SELECT name, price 
FROM products 
WHERE attributes->>'color' = 'Red';

-- 2. 刷新物化视图 (通常在每天凌晨定时任务执行)
REFRESH MATERIALIZED VIEW CONCURRENTLY daily_sales_report;

-- 3. 查询昨天的销售冠军分类
SELECT category, total_revenue 
FROM daily_sales_report 
WHERE sale_date = CURRENT_DATE - INTERVAL '1 day'
ORDER BY total_revenue DESC 
LIMIT 1;

案例总结

这个综合案例展示了 PostgreSQL 16 的核心优势:

  1. 数据完整性 : 通过外键和 CHECK 约束保证。
  2. 自动化逻辑 : 使用 PL/pgSQL 触发器自动处理库存扣减和校验,避免应用层逻辑漏洞。
  3. 高性能分析 : 利用 MATERIALIZED VIEW 预计算复杂聚合结果,并通过 CONCURRENTLY 实现无锁刷新。
  4. 灵活性 : 使用 JSONB 存储非结构化属性,同时享受索引带来的查询速度。
  5. 事务安全: 整个下单过程在事务中完成,确保要么全成功,要么全失败。

通过以上步骤,您已经在 Windows 上成功安装了 PostgreSQL 16,并掌握了从基础建表到高级流式/事务处理的完整技能树。

相关推荐
谪星·阿凯18 小时前
SQL注入漏洞进阶篇:从盲注到WAF绕过的全面解析
数据库·sql·计算机网络
hua8722218 小时前
Golang 构建学习
java·开发语言·学习
快乐柠檬不快乐18 小时前
使用Python操作文件和目录(os, pathlib, shutil)
jvm·数据库·python
V1ncent Chen19 小时前
SQL大师之路 13 聚合函数和分组
数据库·sql·mysql·数据分析
赵渝强老师19 小时前
【赵渝强老师】高斯数据库(openGauss)的体系架构
数据库·postgresql·opengauss·gaussdb·国产数据库
IvorySQL19 小时前
开源同行,感谢有你|IvorySQL 社区邀您领取贡献者证书
数据库·postgresql·开源
IvorySQL20 小时前
PostgreSQL 技术日报 (3月19日)|当 AI 代理开始批量创建数据库
数据库·postgresql·开源
2401_8747325320 小时前
Python上下文管理器(with语句)的原理与实践
jvm·数据库·python
l1t20 小时前
与系统库同名python脚本文件引起的奇怪错误及其解决
开发语言·数据库·python
星空露珠20 小时前
迷你世界UGC3.0脚本Wiki角色模块管理接口 Actor
开发语言·数据库·算法·游戏·lua