PostgreSQL 快速入门
PostgreSQL 操作数据库命令语法
操作类型 | 语法 | 说明 | 示例 |
---|---|---|---|
创建数据库 | CREATE DATABASE database_name [WITH options]; | 创建一个新数据库。可选参数包括编码、拥有者等。 | CREATE DATABASE mydb; 创建名为 mydb 的数据库。 |
CREATE DATABASE database_name WITH OWNER = username ENCODING = 'UTF8'; | 指定拥有者和编码创建数据库。 | CREATE DATABASE mydb WITH OWNER = admin ENCODING = 'UTF8'; 创建 mydb ,归 admin 用户,编码 UTF-8。 | |
删除数据库 | DROP DATABASE database_name [WITH (FORCE)]; | 删除指定数据库。FORCE 强制断开所有连接后删除。 | DROP DATABASE mydb; 删除 mydb 数据库。 |
DROP DATABASE IF EXISTS database_name; | 如果数据库存在则删除,不存在也不报错。 | DROP DATABASE IF EXISTS mydb; 安全删除 mydb ,不存在也没事。 | |
修改数据库 | ALTER DATABASE database_name RENAME TO new_name; | 重命名数据库。 | ALTER DATABASE mydb RENAME TO mynewdb; 将 mydb 改名为 mynewdb 。 |
ALTER DATABASE database_name OWNER TO new_owner; | 更改数据库的拥有者。 | ALTER DATABASE mydb OWNER TO admin; 将 mydb 的拥有者改为 admin 。 | |
ALTER DATABASE database_name SET parameter = value; | 修改数据库的配置参数(如连接数限制)。 | ALTER DATABASE mydb SET max_connections = 200; 设置 mydb 最大连接数为 200。 | |
连接数据库 | \c database_name (在 psql 中) | 在 psql 命令行中切换到指定数据库。 | \c mydb 连接到 mydb 数据库。 |
psql -d database_name -U username (命令行连接) | 从终端连接到指定数据库,需要用户名。 | psql -d mydb -U admin 以 admin 用户连接到 mydb 。 | |
查看所有数据库 | SELECT datname FROM pg_database; | 查询当前实例中的所有数据库名称。 | SELECT datname FROM pg_database; 输出: postgres , mydb , template1 等。 |
\l (在 psql 中) | 在 psql 中列出所有数据库及其信息(如拥有者、大小)。 | \l 显示所有数据库列表。 | |
备份数据库 | pg_dump database_name > backup_file.sql (命令行工具) | 导出数据库到 SQL 文件,用于备份。 | pg_dump mydb > mydb_backup.sql 备份 mydb 到 mydb_backup.sql 文件。 |
pg_dump -h host -U username database_name > backup_file.sql | 指定主机和用户备份数据库。 | pg_dump -h localhost -U admin mydb > backup.sql 备份 mydb 到文件。 | |
恢复数据库 | psql -d database_name < backup_file.sql (命令行工具) | 从 SQL 文件恢复数据库(需先创建空数据库)。 | psql -d mydb < mydb_backup.sql 将 mydb_backup.sql 恢复到 mydb 。 |
pg_restore -d database_name backup_file (若备份为自定义格式) | 从自定义格式备份文件恢复数据库。 | pg_restore -d mydb mydb_backup.dump 恢复 mydb 从 .dump 文件。 | |
创建表 | CREATE TABLE table_name (column_name type [constraints]); | 在当前数据库中创建表,默认在 public SCHEMA 中。 | CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50)); 创建 users 表。 |
删除表 | `DROP TABLE table_name [CASCADE | RESTRICT];` | 删除当前数据库中的表。CASCADE 删除关联,RESTRICT 如果有关联则拒绝。 |
查看表列表 | SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'; | 查询当前数据库中指定 SCHEMA 的所有表。 | SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'; 列出 public 中的表。 |
\dt (在 psql 中) | 在 psql 中列出当前数据库的所有表。 | \dt 显示当前数据库的表列表。 | |
修改表结构 | ALTER TABLE table_name ADD COLUMN column_name type; | 向表中添加新列。 | ALTER TABLE users ADD COLUMN age INT; 给 users 表添加 age 列。 |
ALTER TABLE table_name DROP COLUMN column_name; | 删除表中的列。 | ALTER TABLE users DROP COLUMN age; 删除 users 表的 age 列。 | |
ALTER TABLE table_name RENAME COLUMN old_name TO new_name; | 重命名表中的列。 | ALTER TABLE users RENAME COLUMN name TO username; 将 name 改名为 username 。 | |
插入数据 | INSERT INTO table_name (column1, column2) VALUES (value1, value2); | 向表中插入数据。 | INSERT INTO users (id, name) VALUES (1, '小明'); 插入一条记录到 users 表。 |
查询数据 | SELECT column_name FROM table_name [WHERE condition]; | 从表中查询数据,可加条件。 | SELECT name FROM users WHERE id = 1; 查询 id=1 的用户姓名。 |
更新数据 | UPDATE table_name SET column_name = value [WHERE condition]; | 更新表中的数据,可加条件。 | UPDATE users SET name = '小红' WHERE id = 1; 将 id=1 的名字改为 小红 。 |
删除数据 | DELETE FROM table_name [WHERE condition]; | 删除表中的数据,可加条件。 | DELETE FROM users WHERE id = 1; 删除 id=1 的记录。 |
创建用户 | CREATE ROLE username WITH LOGIN PASSWORD 'password'; | 创建一个可登录的用户(角色)。 | CREATE ROLE admin WITH LOGIN PASSWORD '123456'; 创建用户 admin ,密码 123456 。 |
授权数据库 | GRANT privileges ON DATABASE database_name TO username; | 给用户授予数据库权限(如 ALL , SELECT )。 | GRANT ALL ON DATABASE mydb TO admin; 给 admin 赋予 mydb 的所有权限。 |
撤销权限 | REVOKE privileges ON DATABASE database_name FROM username; | 撤销用户的数据库权限。 | REVOKE ALL ON DATABASE mydb FROM admin; 撤销 admin 在 mydb 上的所有权限。 |
PostgreSQL 数据类型
数据类型 | 存储内容 | 用途示例 | 通俗解释 |
---|---|---|---|
SMALLINT | 小整数 (-32,768 到 32,767) | 年龄、班级编号 | 小号盒子,装小份数字 |
INTEGER (INT) | 整数 (-2亿多 到 2亿多) | 用户 ID、商品数量 | 中号盒子,装常用数字 |
BIGINT | 大整数 (-9千亿亿 到 9千亿亿) | 银行余额、全球人口 | 大号盒子,装超大数字 |
DECIMAL / NUMERIC | 自定义精度的数字(带小数) | 金额(3.14、100.50) | 计算器,精确存钱和分数 |
REAL | 6位精度浮点数 | 温度、身高 | 近似小数盒,存不太精确的数字 |
DOUBLE PRECISION | 15位精度浮点数 | 科学计算数据 | 高精度小数盒,存很精确的数字 |
CHAR(n) | 固定长度字符串(n 个字符) | 邮编(6位)、性别(M/F) | 定长信封,装固定大小的字 |
VARCHAR(n) | 可变长度字符串(最大 n 个字符) | 名字、地址 | 伸缩袋子,装大小不定的字 |
TEXT | 无长度限制的字符串 | 文章、评论 | 大口袋,装多少字都行 |
BOOLEAN | TRUE、FALSE 或 NULL | 是否已婚、是否通过考试 | 开关,只有开和关两种状态 |
DATE | 日期(年-月-日) | 生日、订单日期 | 日历,记年月日 |
TIME | 时间(时:分:秒) | 会议开始时间 | 时钟,记几点几分 |
TIMESTAMP | 日期+时间(无时区) | 事件时间(2025-03-09 14:30:00) | 邮戳,记完整时间 |
TIMESTAMPTZ | 日期+时间(带时区) | 国际航班时间 | 全球邮戳,带时区的时间 |
INTERVAL | 时间段(几天几小时) | 借书期限(3天、2小时) | 计时器,记一段时间 |
BYTEA | 二进制数据 | 图片、视频文件 | U盘,存原始字节流 |
ENUM | 自定义固定值集合 | 心情(happy/sad)、订单状态 | 选择题,只能挑几个固定答案 |
ARRAY | 一组同类型数据 | 成绩([90, 85, 88])、标签 | 筐子,装一堆东西 |
JSON | JSON 格式文本 | 商品属性({“name”: “鞋”, “size”: 42}) | 便签本,记结构化信息 |
JSONB | 二进制 JSON(支持查询和索引) | 复杂商品属性查询 | 智能便签,带索引的高级本子 |
POINT | 坐标点(x, y) | 地图上的位置 | 地图上的一个点 |
PostGIS 扩展 | 地理数据(经纬度、区域等) | 导航、定位 | 高级导航仪,存地图信息 |
INET | IP 地址(IPv4/IPv6) | 用户登录 IP(192.168.1.1) | 网络门牌号 |
CIDR | 网络地址范围 | 子网范围(192.168.1.0/24) | 网络地盘范围 |
MACADDR | MAC 地址 | 设备地址(00:1A:2B:3C:4D:5E) | 设备身份证号 |
UUID | 全球唯一标识符(128位) | 订单号(550e8400-e29b-41d4-…) | 宇宙身份证,独一无二 |
INT4RANGE 等范围 | 范围值(如 [1, 10)) | 时间段、价格区间 | 划地盘,标出一段范围 |
XML | XML 格式数据 | 结构化文档 | 文件夹,存 XML 文件 |
MONEY | 货币金额 | 价格(¥100.50) | 钱包,存带货币符号的金额 |
约束 (Constraints)
什么是约束? 约束是数据库的“规矩”,确保数据符合规则,防止乱七八糟的数据塞进来。
约束类型 | 说明 | 通俗理解 | 示例 |
---|---|---|---|
NOT NULL | 列不能是空值(NULL)。 | “这格必须填,不能留空!” | CREATE TABLE users (id INT NOT NULL, name VARCHAR); |
UNIQUE | 列值不能重复,但允许 NULL(多个 NULL 不算重复)。 | “每个人身份证号不能一样!” | CREATE TABLE users (email VARCHAR UNIQUE); |
PRIMARY KEY | 唯一且非空的列,用来标识每行记录。 | “每人一个独一无二的学号!” | CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR); |
FOREIGN KEY | 列值必须引用另一张表的主键或唯一键,确保关联有效。 | “学生的班级必须是真实班级!” | CREATE TABLE orders (id INT, user_id INT REFERENCES users(id)); |
CHECK | 列值必须满足指定条件。 | “年龄不能是负数!” | CREATE TABLE users (age INT CHECK (age >= 0)); |
EXCLUDE (高级) | 防止表中某些值的组合重复(需要扩展支持,如 GiST)。 | “会议室不能同时被两个人预定!” | CREATE TABLE bookings (room INT, time TSTZRANGE, EXCLUDE USING gist (room WITH =, time WITH &&)); |
多表关联查询 (JOIN)
什么是关联查询? 把多张表拼起来查,就像把几页名单拼成一份大表格。
JOIN 类型 | 说明 | 通俗理解 | 示例 |
---|---|---|---|
INNER JOIN | 只返回两表匹配的行。 | “只找两边都有的记录!” | SELECT u.name, o.order_date FROM users u INNER JOIN orders o ON u.id = o.user_id; |
LEFT JOIN | 返回左表所有行,右表匹配不上就填 NULL。 | “左边全要,右边有就带上!” | SELECT u.name, o.order_date FROM users u LEFT JOIN orders o ON u.id = o.user_id; |
RIGHT JOIN | 返回右表所有行,左表匹配不上就填 NULL。 | “右边全要,左边有就带上!” | SELECT u.name, o.order_date FROM users u RIGHT JOIN orders o ON u.id = o.user_id; |
FULL JOIN | 返回两表所有行,匹配不上的填 NULL。 | “两边全要,没配对的也留着!” | SELECT u.name, o.order_date FROM users u FULL JOIN orders o ON u.id = o.user_id; |
CROSS JOIN | 两表每行交叉组合(笛卡尔积)。 | “所有人跟所有订单配一遍!” | SELECT u.name, o.order_date FROM users u CROSS JOIN orders o; |
别名 (Alias)
- 用
AS
或直接写简称给表或列起个“昵称”,让查询更简洁。 - 示例:
SELECT u.name AS username FROM users u;
- 通俗理解:“给表和列取个小名,写起来不那么累!”
触发器 (Triggers)
什么是触发器? 触发器是表的“自动反应”,某事发生时自动执行操作。
- 用途:记录日志、检查数据、同步表。
- 语法:
CREATE TRIGGER trigger_name BEFORE | AFTER event (INSERT | UPDATE | DELETE) ON table_name FOR EACH ROW EXECUTE FUNCTION function_name();
- 通俗理解:“表的小助手,有人改数据时它就跳出来干活!”
示例:
CREATE FUNCTION log_update() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (table_name, changed_at) VALUES ('users', NOW());
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER user_update_log
AFTER UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION log_update();
- 效果:每次更新
users
表,audit_log
都会记一笔。
索引 (Indexes)
什么是索引? 索引是表的“目录”,加速查找,减少翻遍全书的麻烦。
索引类型 | 说明 | 通俗理解 | 示例 |
---|---|---|---|
B-Tree | 默认索引,适合等值和范围查询。 | “普通目录,按顺序查!” | CREATE INDEX idx_name ON users(name); |
GiST | 通用索引,适合几何、范围查询。 | “高级目录,查地图和时间!” | CREATE INDEX idx_time ON bookings USING gist(time); |
GIN | 倒排索引,适合数组、JSON、全文搜索。 | “搜索目录,查关键词快!” | CREATE INDEX idx_tags ON articles USING gin(tags); |
BRIN | 块范围索引,适合大数据有序列。 | “粗略目录,查大表省空间!” | CREATE INDEX idx_date ON logs USING brin(timestamp); |
- 语法:
CREATE INDEX index_name ON table_name(column_name);
- 通俗理解:“给表加个快查手册,找东西不用一行行翻!”
最新特性:
- 并行索引创建:
CREATE INDEX ... WITH (PARALLEL_WORKERS = 4);
,加速大表索引构建。 - 覆盖索引:
CREATE INDEX idx_cover ON users(id) INCLUDE (name);
,查询时不用访问表。
视图 (Views)
什么是视图? 视图是表的“虚拟窗口”,基于查询结果,像个快捷方式。
- 语法:
CREATE VIEW view_name AS SELECT ...;
- 通俗理解:“把复杂查询存下来,随时看,不用每次重写!”
示例:
CREATE VIEW active_users AS
SELECT id, name FROM users WHERE status = 'active';
- 效果:
SELECT * FROM active_users;
直接看活跃用户。
事务(Transactions)
什么是事务? 事务是一组操作,要么全成功,要么全取消,保证数据不乱。
- 语法:
BEGIN; -- 操作1 -- 操作2 COMMIT; -- 成功提交 -- 或 ROLLBACK; -- 失败回滚
- 通俗理解:“一篮子任务,要么全做完,要么全撤销,像转账不能只扣不加!”
示例:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
锁 (Locks)
什么是锁? 锁是数据库的“门锁”,防止多人同时改数据出错。
锁类型 | 说明 | 通俗理解 | 示例 |
---|---|---|---|
行锁 (ROW) | 锁住某行,别人不能改。 | “这行我先用,你等会!” | SELECT * FROM users WHERE id = 1 FOR UPDATE; |
表锁 (TABLE) | 锁住整张表,如 SHARE (读锁)、EXCLUSIVE (写锁)。 | “整张表我包了,别动!” | LOCK TABLE users IN EXCLUSIVE MODE; |
死锁 | 两事务互相等对方解锁,卡住。 | “你等我,我等你,谁也不动!” | 系统自动检测并终止一个事务。 |
- 通俗理解:“锁是交通信号灯,控制谁能动,谁得等!”
函数 (Functions)
什么是函数? 函数是数据库的“自定义工具”,写一段代码反复用。
- 语法:
CREATE FUNCTION function_name(params) RETURNS type AS $$ BEGIN -- 逻辑 END; $$ LANGUAGE plpgsql;
- 通俗理解:“自己造个小机器人,干重复活!”
示例:
CREATE FUNCTION add_numbers(a INT, b INT) RETURNS INT AS $$
BEGIN
RETURN a + b;
END;
$$ LANGUAGE plpgsql;
- 使用:
SELECT add_numbers(3, 5);
输出 8。
补充知识点
知识点 | 说明 | 通俗理解 | 示例 |
---|---|---|---|
序列 (Sequences) | 自动生成递增数字,常用于主键。 | “自动编号机!” | CREATE SEQUENCE user_seq; INSERT INTO users (id) VALUES (nextval('user_seq')); |
分区表 | 把大表拆成小块,按范围或列表分。 | “大书拆成小册子,好查!” | CREATE TABLE logs (id INT, ts TIMESTAMP) PARTITION BY RANGE (ts); |
全文搜索 | 搜索文本内容,支持关键词和高亮。 | “数据库里的搜索引擎!” | SELECT * FROM articles WHERE to_tsvector(content) @@ to_tsquery('good & news'); |
表空间 (Tablespaces) | 指定数据存储的物理位置。 | “换个硬盘存数据!” | CREATE TABLESPACE fastdisk LOCATION '/ssd/pgdata'; |
角色与权限 | 管理用户和访问权限。 | “谁能看谁能改的门禁卡!” | GRANT SELECT ON users TO reader; |
通俗总结
- 约束:表的规矩,防乱填。
- 关联查询:拼表找数据,别名是小助手。
- 触发器:表的小机器人,自动干活。
- 索引:表的快查目录,找得快。
- 视图:表的快捷窗口,省事。
- 事务:一篮子任务,全成或全废。
- 锁:表的门锁,防抢。
- 函数:自定义工具,偷懒神器。
- 补全:序列编号、分区拆表、搜索文本、权限管理,一个不漏!
什么是 SCHEMA?
在 PostgreSQL 中,SCHEMA 是一个逻辑上的“命名空间”或者“文件夹”,用来组织和管理数据库对象(比如表、视图、索引等)。一个数据库(Database)可以包含多个 SCHEMA,而每个 SCHEMA 里可以有自己的表、视图等东西。
- 比喻:想象一个大仓库(数据库),里面有很多货架(SCHEMA),每个货架上放不同的货物(表、视图等)。SCHEMA 就是帮你把东西分门别类放好。
- 官方定义:SCHEMA 是数据库中的一个逻辑分组,同一个数据库里的 SCHEMA 共享存储空间,但彼此独立命名。
SCHEMA 的作用
- 组织数据
把相关的表归类到一个 SCHEMA 中,方便管理。比如,一个公司数据库可以有
sales
(销售)、hr
(人力资源)、inventory
(库存)三个 SCHEMA。 - 权限控制
可以给不同用户分配不同 SCHEMA 的访问权限。比如,销售团队只能看
sales
的表,HR 只能看hr
的表。 - 避免命名冲突
在同一个数据库里,不同 SCHEMA 可以有同名表。比如
sales.product
和inventory.product
,名字一样但内容不同,不会混淆。 - 模块化开发 大型项目中,不同模块可以用不同 SCHEMA 分开,逻辑更清晰。
在什么情况下要用到 SCHEMA?
- 多用户或多团队场景
- 如果一个数据库被多个团队共用,每个团队可以用自己的 SCHEMA,避免互相干扰。
- 示例:一个学校数据库,老师用
teacher
SCHEMA,学生用student
SCHEMA。
- 复杂项目需要分模块
- 大型应用可能有多个子系统(比如电商的订单、用户、库存),用 SCHEMA 分开更清晰。
- 示例:
orders.order_table
、users.user_table
。
- 权限管理需求
- 需要精细控制谁能访问哪些表时,SCHEMA 是个好工具。
- 示例:财务数据放
finance
SCHEMA,只给财务人员权限。
- 测试和生产环境共存
- 在同一个数据库里,
test
SCHEMA 放测试数据,prod
SCHEMA 放生产数据,方便切换。
- 在同一个数据库里,
什么时候不用 SCHEMA?
如果你的项目很简单,只有一个团队、几个表,数据量也不大,默认的 public
SCHEMA 就够用了。
SCHEMA 是否真实创建了一个数据库?
答案:不是。
- SCHEMA 不是一个独立的数据库,它只是数据库内部的一个逻辑分组。
- 数据库 vs SCHEMA:
- 数据库(Database):是物理隔离的存储单元,创建时会分配独立的空间。不同数据库之间完全独立,比如
mydb1
和mydb2
的数据互不影响。 - SCHEMA:是数据库里的“子文件夹”,所有 SCHEMA 共享同一个数据库的存储空间和连接。切换 SCHEMA 不需要重新连接数据库。
- 数据库(Database):是物理隔离的存储单元,创建时会分配独立的空间。不同数据库之间完全独立,比如
- 比喻:
- 数据库是大房子,SCHEMA 是房子里的房间。建新房子(数据库)需要地基和材料,分房间(SCHEMA)只是画个隔断。
- 证明:
- 创建 SCHEMA:
CREATE SCHEMA myschema;
—— 只是在当前数据库里加了个“文件夹”。 - 创建数据库:
CREATE DATABASE mydb;
—— 这是建了个新“仓库”,完全独立。
- 创建 SCHEMA:
通俗总结
- SCHEMA 是什么:数据库里的“文件夹”,帮你整理表和控制权限。
- 什么时候用:项目复杂、需要分团队或模块时用。简单项目用
public
就行。 - public 行不行:小项目行,大项目不够用。
- 是不是数据库:不是,只是数据库里的分组,不会独立占用空间。
举个例子:
你开个小店,只有一个货架(public
),够用。但如果开了连锁超市,货架得按类别分(fruits
、drinks
),这就是 SCHEMA 的用武之地。