第三章:SQL 基础入门

最后更新: 2024-01-01 作者: PostgreSQL Team
页面目录

第三章:SQL 基础入门

3.1 SQL 概述

SQL(Structured Query Language)是用于管理和操作关系型数据库的标准语言。PostgreSQL 完全遵循 SQL 标准,并提供丰富的扩展功能。

┌──────────────────────────────────────────────────────┐
│                    SQL 语句分类                        │
├──────────────────────────────────────────────────────┤
│  DDL (数据定义语言)  │  CREATE, ALTER, DROP          │
│  DML (数据操作语言)  │  SELECT, INSERT, UPDATE, DELETE│
│  DCL (数据控制语言)  │  GRANT, REVOKE                  │
│  TCL (事务控制语言)  │  COMMIT, ROLLBACK, SAVEPOINT    │
└──────────────────────────────────────────────────────┘

3.2 数据定义语言 (DDL)

3.2.1 创建表

-- 基本创建表语法
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL,
    age INTEGER DEFAULT 18,
    status BOOLEAN DEFAULT true,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

3.2.2 查看表结构

-- 查看表结构
\d users

-- 或
DESCRIBE users;

-- 查看所有表
\dt

-- 查看表及其索引
\d+ users

3.2.3 修改表结构

-- 添加列
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users ADD COLUMN last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP;

-- 修改列
ALTER TABLE users ALTER COLUMN age TYPE SMALLINT;
ALTER TABLE users ALTER COLUMN username SET NOT NULL;

-- 重命名列
ALTER TABLE users RENAME COLUMN phone TO mobile;

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

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

3.2.4 删除表

-- 删除表
DROP TABLE users;

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

-- 级联删除(删除表及所有依赖对象)
DROP TABLE users CASCADE;

-- 删除多个表
DROP TABLE users, orders, products;

3.2.5 临时表

-- 创建临时表
CREATE TEMPORARY TABLE temp_data (
    id INTEGER,
    value TEXT
);

-- 会话级临时表(提交事务后保留)
CREATE TEMP TABLE session_data (
    id SERIAL PRIMARY KEY,
    data TEXT
);

-- 事务级临时表
CREATE TEMP TABLE temp_data (
    id SERIAL PRIMARY KEY,
    data TEXT
) ON COMMIT DELETE ROWS;

3.3 数据操作语言 (DML)

3.3.1 插入数据

-- 插入单行(指定列)
INSERT INTO users (username, email, age) 
VALUES ('张三', 'zhangsan@example.com', 25);

-- 插入单行(所有列)
INSERT INTO users 
VALUES (1, '李四', 'lisi@example.com', 30, true, CURRENT_TIMESTAMP);

-- 插入多行
INSERT INTO users (username, email, age) VALUES
    ('王五', 'wangwu@example.com', 28),
    ('赵六', 'zhaoliu@example.com', 35),
    ('孙七', 'sunqi@example.com', 22);

-- 从其他表插入
INSERT INTO backup_users SELECT * FROM users WHERE created_at > '2024-01-01';

-- 使用 DEFAULT 值
INSERT INTO users (username, email) VALUES ('test', 'test@example.com');

3.3.2 更新数据

-- 更新单列
UPDATE users SET age = 26 WHERE username = '张三';

-- 更新多列
UPDATE users 
SET age = 27, 
    status = false,
    last_login = CURRENT_TIMESTAMP
WHERE username = '李四';

-- 使用表达式更新
UPDATE users 
SET age = age + 1
WHERE age < 30;

-- 使用子查询更新
UPDATE users 
SET email = (
    SELECT new_email 
    FROM email_updates 
    WHERE email_updates.old_email = users.email
)
WHERE EXISTS (
    SELECT 1 FROM email_updates WHERE old_email = users.email
);

3.3.3 删除数据

-- 删除满足条件的行
DELETE FROM users WHERE username = '张三';

-- 删除所有行(快速,但不会重置序列)
DELETE FROM users;

-- 使用 LIMIT 删除
DELETE FROM users 
WHERE id IN (
    SELECT id FROM users ORDER BY created_at LIMIT 100
);

-- 使用 RETURNING 返回删除的行
DELETE FROM users 
WHERE age > 60
RETURNING *;

3.4 数据查询语言 (DQL)

3.4.1 基本 SELECT

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

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

-- 带别名
SELECT 
    username AS "用户名",
    email AS "邮箱",
    age AS "年龄"
FROM users;

-- 使用表达式
SELECT 
    username,
    age,
    age + 5 AS "五年后年龄"
FROM users;

3.4.2 过滤与条件

-- WHERE 子句
SELECT * FROM users WHERE age >= 18;

-- 多条件 AND
SELECT * FROM users 
WHERE age >= 18 AND status = true;

-- 多条件 OR
SELECT * FROM users 
WHERE age < 20 OR age > 60;

-- 组合条件
SELECT * FROM users 
WHERE (age >= 18 AND age <= 30) OR status = true;

-- NOT 条件
SELECT * FROM users WHERE NOT status;

-- IN 运算符
SELECT * FROM users 
WHERE username IN ('张三', '李四', '王五');

-- BETWEEN 运算符
SELECT * FROM users 
WHERE age BETWEEN 18 AND 30;

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

-- ILIKE 不区分大小写匹配
SELECT * FROM users 
WHERE username ILIKE '%张%';

3.4.3 常用运算符

-- 比较运算符
=   -- 等于
<>  -- 不等于
!=  -- 不等于
<   -- 小于
>   -- 大于
<=  -- 小于等于
>=  -- 大于等于

-- 逻辑运算符
AND -- 逻辑与
OR  -- 逻辑或
NOT -- 逻辑非

-- 模式匹配
LIKE    -- 模糊匹配
ILIKE   -- 不区分大小写的模糊匹配
~~      -- LIKE 的等价写法
~~*     -- ILIKE 的等价写法
!~~     -- NOT LIKE 的等价写法

3.4.4 排序与限制

-- 单列排序(升序)
SELECT * FROM users ORDER BY age ASC;

-- 单列排序(降序)
SELECT * FROM users ORDER BY age DESC;

-- 多列排序
SELECT * FROM users 
ORDER BY age DESC, created_at ASC;

-- NULL 值排序(NULL 值排在最前)
SELECT * FROM users ORDER BY age NULLS FIRST;

-- NULL 值排序(NULL 值排在最后)
SELECT * FROM users ORDER BY age DESC NULLS LAST;

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

-- 分页查询
SELECT * FROM users 
ORDER BY id 
LIMIT 10 OFFSET 20;

-- 跳过前 20 条,取 10 条
SELECT * FROM users 
LIMIT 10 
OFFSET ((20 / 10 - 1) * 10);

3.4.5 聚合函数

-- COUNT 计数
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM users WHERE status = true;
SELECT COUNT(DISTINCT username) FROM users;

-- SUM 求和
SELECT SUM(age) FROM users;
SELECT SUM(age) FROM users WHERE status = true;

-- AVG 平均值
SELECT AVG(age) FROM users;

-- MAX 最大值
SELECT MAX(age) FROM users;

-- MIN 最小值
SELECT MIN(age) FROM users;

-- 组合使用
SELECT 
    COUNT(*) AS total_users,
    COUNT(*) FILTER (WHERE status = true) AS active_users,
    AVG(age) AS avg_age,
    MAX(age) AS max_age,
    MIN(age) AS min_age
FROM users;

3.4.6 GROUP BY 分组

-- 基本分组
SELECT status, COUNT(*) FROM users GROUP BY status;

-- 多列分组
SELECT status, age_group, COUNT(*)
FROM (
    SELECT 
        status,
        CASE 
            WHEN age < 20 THEN '青少年'
            WHEN age < 30 THEN '青年'
            WHEN age < 50 THEN '中年'
            ELSE '老年'
        END AS age_group
    FROM users
) t
GROUP BY status, age_group;

-- HAVING 过滤分组
SELECT 
    status, 
    COUNT(*) AS user_count,
    AVG(age) AS avg_age
FROM users 
GROUP BY status
HAVING COUNT(*) > 10;

-- 带有聚合的完整示例
SELECT 
    date_trunc('month', created_at) AS month,
    COUNT(*) AS new_users,
    COUNT(*) FILTER (WHERE status = true) AS active_users,
    AVG(age)::NUMERIC(10,2) AS avg_age
FROM users
WHERE created_at >= '2024-01-01'
GROUP BY date_trunc('month', created_at)
ORDER BY month DESC;

3.5 表连接 (JOIN)

3.5.1 内连接 (INNER JOIN)

-- 基本内连接
SELECT 
    u.username,
    o.order_id,
    o.total_amount,
    o.created_at
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

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

3.5.2 左连接 (LEFT JOIN)

-- 左连接:包含左表所有记录
SELECT 
    u.username,
    o.order_id,
    o.total_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;

-- 找出没有订单的用户
SELECT u.username
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.order_id IS NULL;

3.5.3 右连接 (RIGHT JOIN)

-- 右连接:包含右表所有记录
SELECT 
    u.username,
    o.order_id,
    o.total_amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;

3.5.4 全连接 (FULL OUTER JOIN)

-- 全连接:包含两个表的所有记录
SELECT 
    u.username,
    o.order_id
FROM users u
FULL OUTER JOIN orders o ON u.id = o.user_id;

3.5.5 连接类型图示

INNER JOIN          LEFT JOIN           RIGHT JOIN          FULL JOIN
┌───┬───┐          ┌───┬───┐           ┌───┬───┐           ┌───┬───┐
│ A │ B │           │ A │ B │           │ A │ B │           │ A │ B │
├───┼───┤           ├───┼───┤           ├───┼───┤           ├───┼───┤
│ 1 │ X │           │ 1 │ X │           │ 1 │ X │           │ 1 │ X │
│ 2 │ Y │           │ 2 │ Y │           │   │ Z │           │ 2 │ Y │
│ 3 │   │           │ 3 │   │ ← NULL     │   │   │           │   │ Z │
└───┴───┘           └───┴───┘           └───┴───┘           └───┴───┘

3.6 子查询

3.6.1 标量子查询

-- 返回单个值
SELECT 
    username,
    age,
    (SELECT AVG(age) FROM users) AS avg_age,
    age - (SELECT AVG(age) FROM users) AS diff_from_avg
FROM users;

3.6.2 表子查询

-- 在 FROM 中使用子查询
SELECT 
    status,
    COUNT(*) AS user_count
FROM (
    SELECT 
        *,
        CASE 
            WHEN age < 30 THEN 'young'
            ELSE 'senior'
        END AS age_category
    FROM users
) t
GROUP BY status, age_category;

3.6.3 IN/NOT IN 子查询

-- IN 子查询
SELECT * FROM products
WHERE category_id IN (
    SELECT id FROM categories WHERE name LIKE '%电子%'
);

-- NOT IN 子查询(注意 NULL 问题)
SELECT * FROM users
WHERE id NOT IN (
    SELECT user_id FROM orders WHERE status = 'completed'
);

3.6.4 EXISTS/NOT EXISTS 子查询

-- EXISTS 子查询
SELECT * FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o 
    WHERE o.user_id = u.id AND o.total_amount > 1000
);

-- NOT EXISTS 子查询
SELECT * FROM categories c
WHERE NOT EXISTS (
    SELECT 1 FROM products p 
    WHERE p.category_id = c.id
);

3.7 联合查询 (UNION)

-- UNION:合并并去重
SELECT username, email FROM users
UNION
SELECT admin_name, admin_email FROM admins;

-- UNION ALL:合并保留重复
SELECT username FROM users
UNION ALL
SELECT admin_name FROM admins;

-- 带有 ORDER BY
(SELECT username, email, 'user' AS source FROM users)
UNION
(SELECT admin_name, admin_email, 'admin' AS source FROM admins)
ORDER BY username;

3.8 条件表达式

3.8.1 CASE 表达式

-- 简单 CASE
SELECT 
    username,
    age,
    CASE age
        WHEN 1 THEN '婴儿'
        WHEN 2 THEN '幼儿'
        WHEN 3 THEN '儿童'
        ELSE '其他'
    END AS age_description
FROM users;

-- 搜索 CASE
SELECT 
    username,
    salary,
    CASE 
        WHEN salary < 3000 THEN '低薪'
        WHEN salary >= 3000 AND salary < 8000 THEN '中等'
        WHEN salary >= 8000 THEN '高薪'
        ELSE '未知'
    END AS salary_level
FROM employees;

3.8.2 COALESCE 函数

-- 返回第一个非 NULL 值
SELECT 
    username,
    COALESCE(phone, mobile, email, '无联系方式') AS contact
FROM users;

3.8.3 NULLIF 函数

-- 如果两个值相等返回 NULL,否则返回第一个值
SELECT 
    product_name,
    price,
    NULLIF(price, 0) AS non_zero_price  -- 如果 price 是 0 则返回 NULL
FROM products;

3.8.4 GREATEST 和 LEAST

-- 返回最大值
SELECT GREATEST(10, 20, 5, 30);  -- 结果: 30

-- 返回最小值
SELECT LEAST(10, 20, 5, 30);     -- 结果: 5

-- 在查询中使用
SELECT 
    username,
    math_score,
    english_score,
    GREATEST(math_score, english_score) AS best_score
FROM students;

3.9 本章小结

本章介绍了 PostgreSQL 的 SQL 基础操作:

分类 核心语句
DDL CREATE TABLE, ALTER TABLE, DROP TABLE
DML INSERT, UPDATE, DELETE
DQL SELECT, WHERE, ORDER BY, GROUP BY
连接 INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN
高级 子查询, UNION, CASE 表达式

📌 下一章预告

下一章将深入介绍 PostgreSQL 的数据类型,包括内置类型和高级类型如 JSON、数组等。