PostgreSQL 实战核心:登录、类型、结构与数据的增删改查指南

PostgreSQL 实战核心:登录、类型、结构与数据的增删改查指南

在日常的数据库开发中,掌握最核心的语法即可解决绝大多数需求。本文将 PostgreSQL 的操作分为连接登录、核心数据类型、结构定义(DDL)、数据操纵(DML)、外键机制以及进阶用法,为您梳理最常用、最基础的语句,帮助您快速上手并规避常见陷阱。

前篇:连接与登录

高频提示 :日常开发中,最常用的连接方式是通过命令行工具 psql 或图形界面工具(如 pgAdmin、DBeaver)。掌握命令行登录是最基础的内功。

1. 本地基本登录

bash 复制代码
# 格式:psql -U 用户名 -d 数据库名 -h 主机地址 -p 端口
# 本地默认登录(使用 postgres 超级用户,连接默认 postgres 库)
psql -U postgres

2. 远程登录

bash 复制代码
# 连接远程服务器的指定数据库
psql -U myuser -d my_database -h 192.168.1.100 -p 5432
# 执行后会提示输入密码

3. 退出登录

bash 复制代码
# 在 psql 交互式命令行中输入以下任一命令退出
\q
# 或者
exit

避坑指南:首次安装 PostgreSQL 后,默认会创建一个名为 postgres 的操作系统用户和数据库超级用户。若无法登录或提示密码错误,需检查 pg_hba.conf 配置文件中的认证规则。

4. 补充:高频元命令速记

在日常的数据库操作中,你只需要掌握约 20% 的核心元命令,就能解决 80% 的实际工作需求。不用一开始就背熟所有的元命令,按核心需求来筛选,日常最常用的 psql 命令应该是这几个:

  • \l\c:连入服务器后,先看看有哪些数据库(\l),然后连接到目标库(\c my_database)。
  • \d\dt:这是最高频的操作。进库后查看有哪些表(\dt),以及查看具体某张表的结构(\d table_name)。
  • \x:当表字段很多,或者某列文本很长时,默认的表格排版会很难看。随手敲一个 \x 切换成竖排显示,能极大提升阅读体验。
  • \q:干完活,退出。
  • \?:剩下的那 80% 不常用的命令,平时不需要死记硬背。遇到忘了的,直接用 \? 查阅即可。
    把上面这最常用的几个用熟,就能应付绝大多数场景了。

上篇:核心数据类型

在动手建表之前,必须搞懂最基础的数据类型。PostgreSQL 的数据类型极其丰富,但掌握以下几类核心类型,足以应对绝大部分业务场景。

1. 整数类型

  • INT (或 INTEGER):最常用的整数类型,存储范围足够覆盖日常计数。
  • BIGINT:更大的整数,适用于流水号、海量数据自增ID。
  • SERIAL :伪类型,本质是自动递增的整数。在建表时用作主键,PG 会自动为其创建序列。
    2. 字符串类型
  • VARCHAR(n):变长字符,最大长度为 n。适合存有明确长度上限的文本(如姓名、标题)。
  • TEXT:变长字符,无长度上限。在 PG 中,VARCHAR 和 TEXT 的性能几乎没有差异,因此存长文本(如文章内容、备注)首选 TEXT。
  • CHAR(n) :定长字符,不足长度自动补空格。极少使用。
    3. 日期时间类型
  • DATE:只存日期(如 2023-10-01),不包含时间。
  • TIMESTAMP:存日期加时间(如 2023-10-01 14:30:00),不带时区。日常建表最常用。
  • TIMESTAMPTZ :带时区的日期时间。适用于跨时区的全球化业务系统。
    4. 布尔与精确数值
  • BOOLEAN :布尔类型,只能存 truefalseNULL。常用于表示状态(如是否启用、是否删除)。
  • NUMERIC(p, s) :精确小数。p代表总位数,s代表小数位数。涉及金额、费率等不容许精度丢失的场景,必须用此类型(如 NUMERIC(10,2) 表示最大8位整数,2位小数)。
    核心记忆法:主键自增用 SERIAL,短文本用 VARCHAR,长文本用 TEXT,时间用 TIMESTAMP,金额用 NUMERIC,真假用 BOOLEAN。

中篇:结构定义操作(DDL)

针对数据库、表、列的结构操作,核心在于建、删、改、查。我们先从宏观到微观,依次梳理。

一、 数据库

高频提示 :日常开发中,数据库最常用的操作就是"创建、切换、删除",修改数据库名极少使用。

1. 增

sql 复制代码
-- 最简创建数据库
CREATE DATABASE my_database;

2. 删

sql 复制代码
-- 删除数据库(慎用!库内所有表和数据全部消失,需确保当前无活动连接)
DROP DATABASE my_database;

3. 改

sql 复制代码
-- 修改数据库名称
ALTER DATABASE my_database RENAME TO new_database;

4. 查

sql 复制代码
-- 查看当前实例下所有数据库(过滤掉系统模板库)
SELECT datname FROM pg_database WHERE datistemplate = false;

二、 表

高频提示 :表最常用的操作是"创建(带主键)、清空数据(截断)、删除"。

1. 增

sql 复制代码
-- 切换到目标数据库(在 psql 命令行中使用 \c 命令)
\c my_database
-- 创建表(应用核心数据类型,必须定义主键)
CREATE TABLE student (
    id SERIAL PRIMARY KEY,             -- 自增主键
    name VARCHAR(50) NOT NULL,         -- 变长字符串
    age INT,                           -- 整数
    is_active BOOLEAN DEFAULT true,    -- 布尔值,默认为真
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 日期时间,默认当前时间
);

2. 删

sql 复制代码
-- 彻底删除表(结构和数据一起删除)
DROP TABLE student;
-- 仅删除所有数据,但保留表结构(比 DELETE 快,且重置序列,极常用)
TRUNCATE TABLE student RESTART IDENTITY;

3. 改

sql 复制代码
-- 修改表名
ALTER TABLE student RENAME TO new_student;

4. 查

sql 复制代码
-- 查看当前数据库 public 模式下的所有表
SELECT tablename FROM pg_tables WHERE schemaname = 'public';

三、 列

高频提示 :代码开发中,需求变更是常态,因此对列的"增、改"是最高频的操作。删除列需确认无依赖。

1. 增

sql 复制代码
-- 向已有表中添加新列
ALTER TABLE student ADD COLUMN gender VARCHAR(2);

2. 删

sql 复制代码
-- 删除不需要的列
ALTER TABLE student DROP COLUMN gender;

3. 改(两种常见需求)

sql 复制代码
-- 需求A:修改列的数据类型/长度
ALTER TABLE student ALTER COLUMN name TYPE VARCHAR(100); 
-- 需求B:修改列名
ALTER TABLE student RENAME COLUMN age TO student_age;

4. 查

sql 复制代码
-- 查看 student 表的所有列信息
SELECT column_name, data_type, character_maximum_length, is_nullable 
FROM information_schema.columns 
WHERE table_name = 'student';

结构操作速记卡:

操作对象
数据库 CREATE DATABASE DROP DATABASE ALTER DATABASE...RENAME TO SELECT FROM pg_database
CREATE TABLE DROP TABLE / TRUNCATE TABLE ALTER TABLE...RENAME TO SELECT FROM pg_tables
ALTER TABLE...ADD COLUMN ALTER TABLE...DROP COLUMN ALTER TABLE...ALTER COLUMN / RENAME COLUMN SELECT FROM information_schema

下篇:数据操作(DML)

针对数据本身的操作,这是日常开发中使用频率最高的部分。掌握以下核心语法,足以应对绝大部分业务场景。

假设操作表student (id, name, age, gender, dept)

一、 增

1. 核心语法:单行/批量插入

sql 复制代码
-- 推荐写法:显式指定列名(防错,即使以后表结构加列也不会报错)
INSERT INTO student (name, age, gender, dept) 
VALUES ('张三', 20, '男', '计算机系');

2. PG特色语法:插入并返回数据

sql 复制代码
-- 插入数据后,直接返回自增生成的 id,免去再次查询
INSERT INTO student (name, age) 
VALUES ('李四', 21) 
RETURNING id, name;

避坑指南:尽量少用 INSERT INTO student VALUES (...) 这种不写列名的写法,一旦表新增了字段,代码直接报错。

二、 删

1. 核心语法:条件删除

sql 复制代码
-- 删除特定数据
DELETE FROM student WHERE id = 1;

2. 高频语法:清空全表

sql 复制代码
-- 删除表中所有数据,速度比 DELETE 快得多,且重置序列
TRUNCATE TABLE student; 

避坑指南:执行 DELETE 前,一定一定一定要检查有没有 WHERE 条件!没有条件就是灾难。

三、 改

1. 核心语法:条件修改

sql 复制代码
-- 修改单个字段
UPDATE student SET age = 22 WHERE id = 1;
-- 修改多个字段(用逗号隔开)
UPDATE student SET age = 22, dept = '软件系' WHERE id = 1;

2. PG特色语法:更新并返回

sql 复制代码
-- 更新数据后,直接返回更新后的记录
UPDATE student SET age = 23 WHERE id = 1 RETURNING *;

避坑指南:执行 UPDATE 前,先用 SELECT 查一下 WHERE 条件过滤出的数据对不对,确认无误再把 SELECT 改成 UPDATE

四、 查(重点)

查询是 SQL 的灵魂,占据了大部分工作量。PostgreSQL 的查询功能极其强大,但最常用的组合如下:

1. 基础查询

sql 复制代码
-- 查所有(生产环境慎用 *,影响性能)
SELECT * FROM student;
-- 查指定列(推荐)
SELECT name, age FROM student;
-- 去重查询(查看有哪些院系)
SELECT DISTINCT dept FROM student;

2. 条件查询

sql 复制代码
-- 多条件组合 (AND / OR)
SELECT * FROM student WHERE dept = '计算机系' AND age > 20;
-- 范围查询 (BETWEEN / IN)
SELECT * FROM student WHERE age BETWEEN 20 AND 25;
SELECT * FROM student WHERE dept IN ('计算机系', '软件系');
-- 模糊查询 (LIKE,%代表任意多个字符,_代表单个字符)
SELECT * FROM student WHERE name LIKE '张%'; -- 查姓张的

3. 排序与限制

sql 复制代码
-- 按年龄降序排列 (DESC 降序,ASC 升序-默认)
SELECT * FROM student ORDER BY age DESC;
-- PG 分页查询基础:LIMIT 限制条数, OFFSET 跳过条数
SELECT * FROM student ORDER BY age DESC LIMIT 10 OFFSET 0; -- 第1页,每页10条

4. 聚合与分组

sql 复制代码
-- 统计每个院系的学生人数和平均年龄
SELECT 
    dept AS "院系", 
    COUNT(*) AS "人数", 
    AVG(age) AS "平均年龄" 
FROM student 
GROUP BY dept
HAVING COUNT(*) > 10; -- HAVING 用于过滤分组后的数据

5. 连表查询(终极核心)

现实业务中数据总在多张表,JOIN 是重中之重。掌握 INNER JOINLEFT JOIN 就够了。

假设有 score (student_id, course_id, grade) 表。

sql 复制代码
-- 内连接:查有成绩的学生及其成绩(两张表必须匹配上才显示)
SELECT s.name, c.course_id, c.grade 
FROM student s 
INNER JOIN score c ON s.id = c.student_id;
-- 左连接:查所有学生,有成绩就显示成绩,没成绩就显示NULL(以左表为准)
SELECT s.name, c.grade 
FROM student s 
LEFT JOIN score c ON s.id = c.student_id;

数据操作速记卡:

操作 核心语法 黄金保命法则
INSERT INTO ... VALUES ... RETURNING ... 永远写上列名列表
DELETE FROM ... WHERE ... 没有 WHERE 的 DELETE 就是灾难!
UPDATE ... SET ... WHERE ... RETURNING ... 没有 WHERE 的 UPDATE 就是灾难!
SELECT ... FROM ... JOIN ... WHERE ... GROUP BY ... ORDER BY ... LIMIT 避免 SELECT *JOIN 前想清楚用 INNER 还是 LEFT

末篇:外键机制

在数据库设计中,外键是用来保证数据一致性的核心机制。理解外键不需要啃厚厚的理论,掌握它的基本概念、建删语法、以及它带来的"限制",就能搞定绝大部分日常工作。

一、 一秒钟看懂外键(概念篇)

外键就像一张"介绍信"或"户口本"。

假设有两张表:class(父表)和 student(子表)。

学生表里有一列 class_id(所属班级)。这个 class_id 不能随便瞎填,必须得在 class 表里真实存在。

  • 父表(主表) :被引用的表(class),提供主键。
  • 子表(从表) :包含外键的表(student),引用父表的主键。
  • 一句话核心:子表的外键,必须在父表的主键里找得到,不能是"野指针"。

二、 外键的增删改(操作篇)

1. 增:建表时直接带上(一步到位)

sql 复制代码
CREATE TABLE student (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    class_id INT,  -- 这个列将作为外键
    -- 声明外键约束
    CONSTRAINT fk_student_class FOREIGN KEY (class_id) REFERENCES class(id)
);

2. 增:表建好后追加外键(最常用)

sql 复制代码
-- 给现有的 student 表增加外键
ALTER TABLE student
ADD CONSTRAINT fk_student_class 
FOREIGN KEY (class_id) REFERENCES class(id);

3. 删:解除外键绑定

sql 复制代码
-- 删除外键约束(注意删的是约束名,不是列名)
ALTER TABLE student
DROP CONSTRAINT fk_student_class;

4. 查:看表上有哪些外键

sql 复制代码
-- 查询 student 表的外键约束信息
SELECT conname AS constraint_name, conrelid::regclass AS table_name
FROM pg_constraint 
WHERE contype = 'f' AND conrelid = 'student'::regclass;

三、 外键的"脾气"(规则篇)

外键的存在感,主要体现在你操作数据时引发的报错上。记住两条铁律即可。

铁律 1:插数据时,子表不能凭空捏造

  • 现象 :往 student 表插入一个 class_id = 99 的学生,但 class 表里根本没有 99 号班级。
  • 结果 :报错!INSERT 语句被拒绝。
  • 解决 :必须先往 class 表里插入 99 号班级,再插学生。
    铁律 2:删数据时,父表不能留"孤儿"
  • 现象 :1 号班级里有 50 个学生,你直接想把 class 表里的 1 号班级删了(DELETE FROM class WHERE id = 1)。
  • 结果 :报错!DELETE 语句被拒绝。
  • 原因:如果班级删了,这 50 个学生就成了"孤儿",数据不一致。
  • 解决:必须先把 1 号班级里的学生全删了(或转走),最后才能删班级。

四、 级联操作(进阶篇)

遇到"铁律2"那种删不掉父表数据的报错,除了手动先删子表,部分场景会用到"级联"。

如果你希望:删父表数据时,子表关联的数据自动跟着删,在建外键时可以加上级联声明。

sql 复制代码
ALTER TABLE student
ADD CONSTRAINT fk_student_class 
FOREIGN KEY (class_id) REFERENCES class(id)
ON DELETE CASCADE   -- 当父表(班级)删除时,子表(学生)自动跟着删除
ON UPDATE CASCADE;  -- 当父表(班级)ID修改时,子表(学生)ID自动跟着修改

注:加了 CASCADE 后,删 class 表的 1 号班级,student 表里 1 号班级的学生会瞬间消失,慎用。

外键速记卡:

操作 核心语法/规则 记忆点
加外键 ALTER TABLE 子表 ADD CONSTRAINT 约束名 FOREIGN KEY (子列) REFERENCES 父表(父列) "子"引用"父"
删外键 ALTER TABLE 子表 DROP CONSTRAINT 约束名 删的是约束,不是列
插数据报错 子表插入了父表没有的 ID 先有爹,后有儿子
删数据报错 父表还有子表数据引用,不让删 儿子还在,爹不能死
级联删除 ON DELETE CASCADE 爹没了,儿子跟着陪葬

避坑指南:在实际的互联网大厂业务开发中,为了追求高并发性能,有时会不建物理外键,而是通过业务代码逻辑来保证数据一致性。但在传统企业级应用、教学系统、小型系统中,物理外键依然是保证数据不脏的"最佳守门员"。


终篇:进阶核心机制

掌握了库表结构与数据的增删改查后,要想让数据库不仅"能跑"而且"跑得快、不出错",必须掌握以下四大核心模块。

一、 索引:查询提速的利器

高频提示 :索引就像字典的目录,没有索引时查数据需要全表扫描,加上索引后查询速度可以提升成百上千倍。但索引不是越多越好,它会拖慢写入速度并占用磁盘。

1. 增:创建索引

sql 复制代码
-- 为 student 表的 name 列创建普通索引,加速按姓名查询
CREATE INDEX idx_student_name ON student (name);

2. 删:删除索引

sql 复制代码
-- 删除不再需要的索引
DROP INDEX idx_student_name;

3. 查:看表上有哪些索引

sql 复制代码
SELECT indexname FROM pg_indexes WHERE tablename = 'student';

核心记忆法

  • 主键自带索引:建表时设为主键的列,数据库会自动为其创建唯一索引,无需重复添加。
  • 外键建议加索引:外键列通常用于连表查询,加上索引能极大提升 JOIN 性能。
  • 避坑指南:不要在小表上建索引;不要在增删改极其频繁的列上建过多索引。

二、 事务控制:数据安全的底线

高频提示 :转账场景中,A扣钱和B加钱必须同时成功或同时失败。事务就是保证这一组操作不可分割的机制。

1. 开启与提交(成功)

sql 复制代码
-- 开启事务
BEGIN;
-- 执行操作
UPDATE account SET balance = balance - 100 WHERE id = 'A';
UPDATE account SET balance = balance + 100 WHERE id = 'B';
-- 确认无误,提交到数据库持久化
COMMIT;

2. 回滚(失败)

sql 复制代码
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 'A';
-- 发现B账户不存在,操作失败,撤销刚才的所有修改
ROLLBACK;

核心记忆法:事务的四大特性(ACID):原子性(不可分割)、一致性(数据正确)、隔离性(并发互不干扰)、持久性(提交即永久)。在应用层代码中操作数据库时,一定要合理配置事务的传播行为和隔离级别,避免脏读。

三、 视图:复杂查询的封装器

高频提示 :视图是一张"虚拟表",它本身不存数据,存的是一条复杂的 SQL 查询语句。常用于简化高频的多表联查,或做权限隔离(只暴露部分列给前端)。

1. 增:创建视图

sql 复制代码
-- 将"学生表关联成绩表"的复杂查询封装成一个视图
CREATE VIEW v_student_score AS
SELECT s.id, s.name, c.course_id, c.grade
FROM student s
LEFT JOIN score c ON s.id = c.student_id;

2. 查:使用视图

sql 复制代码
-- 使用起来和查普通表一模一样,极其方便
SELECT * FROM v_student_score WHERE name = '张三';

3. 改与删

sql 复制代码
-- 修改视图定义
CREATE OR REPLACE VIEW v_student_score AS
SELECT s.id, s.name, c.grade FROM student s LEFT JOIN score c ON s.id = c.student_id;
-- 删除视图
DROP VIEW v_student_score;

核心记忆法 :视图是"只读"的逻辑封装,绝大多数情况下只对视图做 SELECT,不要对视图做 INSERT/UPDATE

四、 常用内置函数:减少代码搬运

高频提示 :很多数据处理直接在 SQL 层面解决,比把数据拉到应用层处理效率高得多。

1. 空值处理(最常用)

sql 复制代码
-- 如果 age 为 NULL,则返回 0
SELECT id, name, COALESCE(age, 0) AS age FROM student;

2. 字符串处理

sql 复制代码
-- 拼接字符串
SELECT id, CONCAT(name, '-', dept) AS info FROM student;
-- 截取与大小写转换
SELECT UPPER(name) AS upper_name, SUBSTRING(name, 1, 1) AS first_char FROM student;

3. 日期处理

sql 复制代码
-- 获取当前时间
SELECT CURRENT_TIMESTAMP;
-- 日期加减计算(查3天后、1年前)
SELECT CURRENT_DATE + INTERVAL '3 day', CURRENT_DATE - INTERVAL '1 year';

核心记忆法 :能用 COALESCE 解决的空值问题,绝不写在业务代码里的 if(x == null);能用 SQL 拼接的字符串,绝不拉回内存里 for 循环拼接。