跳转至

第三章:SQL 基础

SQL 概述

SQL(Structured Query Language)是用于管理关系型数据库的标准语言。PostgreSQL 支持完整的 SQL 标准,并提供了许多扩展功能。

数据类型

数值类型

类型 描述 范围
SMALLINT 2字节整数 -32,768 到 32,767
INTEGER 4字节整数 -2,147,483,648 到 2,147,483,647
BIGINT 8字节整数 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
DECIMAL(p,s) 精确数值 精度 p,小数位数 s
NUMERIC(p,s) 精确数值 同 DECIMAL
REAL 4字节浮点数 6位十进制精度
DOUBLE PRECISION 8字节浮点数 15位十进制精度
SERIAL 自增整数 1 到 2,147,483,647
BIGSERIAL 自增大整数 1 到 9,223,372,036,854,775,807

字符类型

类型 描述 最大长度
CHAR(n) 定长字符串 最多 n 个字符
VARCHAR(n) 变长字符串 最多 n 个字符
TEXT 变长字符串 无限制
BYTEA 二进制数据 无限制

日期时间类型

类型 描述 范围
DATE 日期 4713 BC 到 5874897 AD
TIME 时间 00:00:00 到 24:00:00
TIMESTAMP 日期时间 4713 BC 到 294276 AD
TIMESTAMPTZ 带时区日期时间 4713 BC 到 294276 AD
INTERVAL 时间间隔 -178000000 年到 178000000 年

布尔类型

类型 描述
BOOLEAN 布尔值,true/false

其他类型

类型 描述
UUID 通用唯一标识符
JSON JSON 数据
JSONB 二进制 JSON 数据
ARRAY 数组
HSTORE 键值对存储

创建和管理表

创建表

-- 创建用户表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    is_active BOOLEAN DEFAULT TRUE
);

-- 创建产品表
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL CHECK (price > 0),
    stock_quantity INTEGER DEFAULT 0 CHECK (stock_quantity >= 0),
    category_id INTEGER,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 创建订单表
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id),
    total_amount DECIMAL(10, 2) NOT NULL,
    status VARCHAR(20) DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

修改表结构

-- 添加列
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

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

-- 添加约束
ALTER TABLE users ADD CONSTRAINT phone_unique UNIQUE (phone);

-- 删除列
ALTER TABLE users DROP COLUMN phone;

-- 重命名表
ALTER TABLE users RENAME TO customers;

-- 重命名列
ALTER TABLE users RENAME COLUMN username TO user_name;

删除表

-- 删除表(危险操作)
DROP TABLE users;

-- 删除表(如果存在)
DROP TABLE IF EXISTS users;

-- 级联删除(删除相关对象)
DROP TABLE users CASCADE;

数据操作语言(DML)

INSERT - 插入数据

-- 插入单行数据
INSERT INTO users (username, email, password_hash)
VALUES ('john_doe', 'john@example.com', 'hashed_password');

-- 插入多行数据
INSERT INTO users (username, email, password_hash) VALUES
('jane_smith', 'jane@example.com', 'hashed_password_1'),
('bob_johnson', 'bob@example.com', 'hashed_password_2'),
('alice_williams', 'alice@example.com', 'hashed_password_3');

-- 插入数据并返回结果
INSERT INTO users (username, email, password_hash)
VALUES ('charlie_brown', 'charlie@example.com', 'hashed_password')
RETURNING id, username, created_at;

-- 从查询结果插入
INSERT INTO user_backup (id, username, email)
SELECT id, username, email FROM users WHERE created_at < '2024-01-01';

SELECT - 查询数据

-- 查询所有列
SELECT * FROM users;

-- 查询特定列
SELECT id, username, email FROM users;

-- 使用别名
SELECT 
    id AS user_id,
    username AS user_name,
    email AS email_address
FROM users;

-- 去重查询
SELECT DISTINCT category_id FROM products;

-- 条件查询
SELECT * FROM users WHERE is_active = TRUE;

-- 多条件查询
SELECT * FROM products 
WHERE price > 100 
  AND stock_quantity > 0 
  AND category_id = 1;

-- 范围查询
SELECT * FROM orders 
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';

-- IN 查询
SELECT * FROM users 
WHERE username IN ('john_doe', 'jane_smith', 'bob_johnson');

-- LIKE 模糊查询
SELECT * FROM users 
WHERE email LIKE '%@example.com';

-- 排序
SELECT * FROM products 
ORDER BY price DESC, name ASC;

-- 限制结果数量
SELECT * FROM users 
ORDER BY created_at DESC 
LIMIT 10;

-- 分页查询
SELECT * FROM users 
ORDER BY id 
LIMIT 10 OFFSET 20;  -- 跳过前20条,取10条

UPDATE - 更新数据

-- 更新单行
UPDATE users 
SET email = 'new_email@example.com', updated_at = CURRENT_TIMESTAMP
WHERE id = 1;

-- 更新多行
UPDATE products 
SET price = price * 0.9  -- 打9折
WHERE category_id = 2;

-- 使用子查询更新
UPDATE orders 
SET status = 'completed'
WHERE user_id IN (
    SELECT id FROM users WHERE created_at < '2024-01-01'
);

-- 更新并返回结果
UPDATE users 
SET is_active = FALSE 
WHERE last_login < CURRENT_DATE - INTERVAL '1 year'
RETURNING id, username, email;

DELETE - 删除数据

-- 删除特定行
DELETE FROM users WHERE id = 100;

-- 删除满足条件的行
DELETE FROM orders 
WHERE status = 'cancelled' 
  AND created_at < CURRENT_DATE - INTERVAL '6 months';

-- 删除所有数据(危险!)
DELETE FROM users;

-- 使用子查询删除
DELETE FROM products 
WHERE id IN (
    SELECT product_id FROM order_items WHERE quantity = 0
);

-- 删除并返回结果
DELETE FROM users 
WHERE is_active = FALSE
RETURNING id, username, email;

聚合函数

-- 计数
SELECT COUNT(*) FROM users;
SELECT COUNT(DISTINCT category_id) FROM products;

-- 求和
SELECT SUM(total_amount) FROM orders;
SELECT SUM(quantity * price) FROM order_items;

-- 平均值
SELECT AVG(price) FROM products;
SELECT AVG(total_amount) FROM orders WHERE status = 'completed';

-- 最大值/最小值
SELECT MAX(price) FROM products;
SELECT MIN(created_at) FROM users;

-- 分组聚合
SELECT 
    category_id,
    COUNT(*) as product_count,
    AVG(price) as avg_price,
    SUM(stock_quantity) as total_stock
FROM products
GROUP BY category_id;

-- 分组后过滤
SELECT 
    user_id,
    COUNT(*) as order_count,
    SUM(total_amount) as total_spent
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 5;

连接查询

内连接(INNER JOIN)

-- 获取用户订单信息
SELECT 
    u.username,
    u.email,
    o.id as order_id,
    o.total_amount,
    o.created_at
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

-- 多表连接
SELECT 
    u.username,
    p.name as product_name,
    oi.quantity,
    oi.price,
    o.total_amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN order_items oi ON o.id = oi.order_id
INNER JOIN products p ON oi.product_id = p.id;

左连接(LEFT JOIN)

-- 获取所有用户及其订单(包括没有订单的用户)
SELECT 
    u.username,
    u.email,
    o.id as order_id,
    o.total_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;

-- 使用 COALESCE 处理 NULL
SELECT 
    u.username,
    COALESCE(COUNT(o.id), 0) as order_count,
    COALESCE(SUM(o.total_amount), 0) as total_spent
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username;

右连接(RIGHT JOIN)

-- 获取所有订单及其用户(包括用户已删除的订单)
SELECT 
    o.id as order_id,
    o.total_amount,
    u.username
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;

全外连接(FULL OUTER JOIN)

-- 获取所有用户和所有产品的组合
SELECT 
    u.username,
    p.name as product_name
FROM users u
FULL OUTER JOIN products p ON TRUE
WHERE u.id IS NOT NULL AND p.id IS NOT NULL;

自连接(SELF JOIN)

-- 查找同一部门的员工
SELECT 
    e1.name as employee_name,
    e2.name as colleague_name,
    e1.department
FROM employees e1
INNER JOIN employees e2 ON e1.department = e2.department
WHERE e1.id != e2.id;

子查询

标量子查询

-- 在 SELECT 中使用子查询
SELECT 
    username,
    email,
    (SELECT COUNT(*) FROM orders WHERE user_id = users.id) as order_count
FROM users;

-- 在 WHERE 中使用子查询
SELECT * FROM products
WHERE price > (SELECT AVG(price) FROM products);

-- 在 HAVING 中使用子查询
SELECT category_id, AVG(price) as avg_price
FROM products
GROUP BY category_id
HAVING AVG(price) > (SELECT AVG(price) FROM products);

行子查询

-- 查找价格最高的产品
SELECT * FROM products
WHERE (price, id) = (
    SELECT MAX(price), MIN(id) 
    FROM products 
    WHERE stock_quantity > 0
);

表子查询

-- 使用子查询作为临时表
SELECT 
    category_name,
    product_count,
    avg_price
FROM (
    SELECT 
        c.name as category_name,
        COUNT(p.id) as product_count,
        AVG(p.price) as avg_price
    FROM categories c
    LEFT JOIN products p ON c.id = p.category_id
    GROUP BY c.id, c.name
) as category_stats
WHERE product_count > 0
ORDER BY avg_price DESC;

常用函数

字符串函数

-- 字符串连接
SELECT CONCAT(first_name, ' ', last_name) as full_name FROM users;
SELECT first_name || ' ' || last_name as full_name FROM users;

-- 大小写转换
SELECT UPPER(username), LOWER(email) FROM users;

-- 字符串长度
SELECT LENGTH(username) as name_length FROM users;

-- 子字符串
SELECT SUBSTRING(email FROM 1 FOR POSITION('@' IN email) - 1) as username FROM users;

-- 替换
SELECT REPLACE(description, 'old', 'new') FROM products;

-- 去除空格
SELECT TRIM(BOTH ' ' FROM username) FROM users;

数值函数

-- 四舍五入
SELECT ROUND(price, 2) FROM products;
SELECT CEIL(price), FLOOR(price) FROM products;

-- 绝对值
SELECT ABS(price - 100) as diff_from_100 FROM products;

-- 幂运算
SELECT POWER(2, 10) as two_power_ten;

-- 随机数
SELECT RANDOM() as random_number;

日期时间函数

-- 当前时间
SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP;

-- 提取日期部分
SELECT 
    EXTRACT(YEAR FROM created_at) as year,
    EXTRACT(MONTH FROM created_at) as month,
    EXTRACT(DAY FROM created_at) as day
FROM users;

-- 日期加减
SELECT 
    created_at + INTERVAL '1 day' as tomorrow,
    created_at - INTERVAL '1 month' as last_month
FROM users;

-- 日期格式化
SELECT TO_CHAR(created_at, 'YYYY-MM-DD HH24:MI:SS') as formatted_date FROM users;

事务控制

-- 开始事务
BEGIN;

-- 执行多个操作
INSERT INTO users (username, email) VALUES ('user1', 'user1@example.com');
INSERT INTO orders (user_id, total_amount) VALUES (currval('users_id_seq'), 100.00);

-- 提交事务
COMMIT;

-- 或者回滚事务
ROLLBACK;

-- 使用事务块
BEGIN;
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    -- 如果出现错误,自动回滚
    SAVEPOINT transfer_point;
    -- 可以回滚到保存点
    ROLLBACK TO transfer_point;
COMMIT;

总结

本章介绍了 PostgreSQL 的 SQL 基础,包括: - 数据类型和表创建 - 数据操作(INSERT、SELECT、UPDATE、DELETE) - 聚合函数和分组查询 - 各种连接查询 - 子查询的使用 - 常用函数 - 事务控制

掌握这些基础知识是使用 PostgreSQL 的关键。下一章我们将学习数据类型和表设计的高级技巧。