Supabase表操作 #

一、创建表 #

1.1 使用表编辑器创建 #

text
Dashboard > Table Editor > Create a new table

步骤
├── 输入表名
├── 添加列
├── 设置主键
├── 配置外键
├── 启用RLS
└── 保存

1.2 使用SQL创建 #

sql
-- 基础创建表
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    email TEXT UNIQUE NOT NULL,
    name TEXT,
    avatar_url TEXT
);

-- 完整创建表
CREATE TABLE posts (
    id BIGSERIAL PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    title TEXT NOT NULL,
    content TEXT,
    slug TEXT UNIQUE NOT NULL,
    published BOOLEAN DEFAULT FALSE,
    author_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    view_count INTEGER DEFAULT 0,
    metadata JSONB DEFAULT '{}'::jsonb
);

-- 添加注释
COMMENT ON TABLE posts IS '博客文章表';
COMMENT ON COLUMN posts.title IS '文章标题';

1.3 常用数据类型 #

类型 说明 示例
BIGSERIAL 自增整数 id
TEXT 文本 title, content
INTEGER 整数 count
BIGINT 大整数 user_id
BOOLEAN 布尔 published
TIMESTAMPTZ 时间戳 created_at
DATE 日期 birth_date
NUMERIC 精确数值 price
JSONB JSON对象 metadata
UUID UUID id
BYTEA 二进制 file_data

1.4 创建带默认值的表 #

sql
CREATE TABLE products (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    name TEXT NOT NULL,
    price NUMERIC(10, 2) NOT NULL DEFAULT 0,
    stock INTEGER DEFAULT 0,
    active BOOLEAN DEFAULT true,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    tags TEXT[] DEFAULT '{}',
    attributes JSONB DEFAULT '{}'::jsonb
);

二、表约束 #

2.1 主键约束 #

sql
-- 单列主键
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    name TEXT
);

-- 复合主键
CREATE TABLE order_items (
    order_id BIGINT NOT NULL,
    product_id BIGINT NOT NULL,
    quantity INTEGER,
    PRIMARY KEY (order_id, product_id)
);

-- UUID主键
CREATE TABLE sessions (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    user_id BIGINT NOT NULL
);

2.2 外键约束 #

sql
-- 基础外键
CREATE TABLE comments (
    id BIGSERIAL PRIMARY KEY,
    post_id BIGINT REFERENCES posts(id),
    content TEXT NOT NULL
);

-- 外键选项
CREATE TABLE orders (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
    status TEXT DEFAULT 'pending'
);

-- 外键选项说明
-- ON DELETE CASCADE: 删除父记录时删除子记录
-- ON DELETE SET NULL: 删除父记录时设为NULL
-- ON DELETE RESTRICT: 阻止删除有子记录的父记录
-- ON UPDATE CASCADE: 更新父记录时更新外键

2.3 唯一约束 #

sql
-- 列级唯一约束
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email TEXT UNIQUE NOT NULL,
    username TEXT UNIQUE
);

-- 表级唯一约束
CREATE TABLE user_profiles (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    platform TEXT NOT NULL,
    handle TEXT NOT NULL,
    UNIQUE (platform, handle)
);

-- 添加唯一约束
ALTER TABLE users ADD CONSTRAINT unique_phone UNIQUE (phone);

2.4 检查约束 #

sql
-- 列级检查约束
CREATE TABLE products (
    id BIGSERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    price NUMERIC(10, 2) CHECK (price >= 0),
    stock INTEGER CHECK (stock >= 0)
);

-- 表级检查约束
CREATE TABLE orders (
    id BIGSERIAL PRIMARY KEY,
    status TEXT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL,
    completed_at TIMESTAMPTZ,
    CONSTRAINT valid_dates CHECK (completed_at IS NULL OR completed_at >= created_at)
);

-- 添加检查约束
ALTER TABLE products ADD CONSTRAINT positive_price CHECK (price > 0);

2.5 非空约束 #

sql
CREATE TABLE articles (
    id BIGSERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    author_id BIGINT NOT NULL REFERENCES users(id),
    published_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

三、修改表 #

3.1 添加列 #

sql
-- 添加单列
ALTER TABLE users ADD COLUMN phone TEXT;

-- 添加带约束的列
ALTER TABLE users ADD COLUMN age INTEGER CHECK (age >= 0);

-- 添加带默认值的列
ALTER TABLE users ADD COLUMN is_active BOOLEAN DEFAULT true;

-- 添加多列
ALTER TABLE users 
    ADD COLUMN bio TEXT,
    ADD COLUMN website TEXT;

3.2 修改列 #

sql
-- 修改数据类型
ALTER TABLE users ALTER COLUMN name TYPE VARCHAR(100);

-- 修改默认值
ALTER TABLE users ALTER COLUMN is_active SET DEFAULT false;

-- 删除默认值
ALTER TABLE users ALTER COLUMN is_active DROP DEFAULT;

-- 设置非空
ALTER TABLE users ALTER COLUMN name SET NOT NULL;

-- 取消非空
ALTER TABLE users ALTER COLUMN name DROP NOT NULL;

3.3 重命名 #

sql
-- 重命名表
ALTER TABLE users RENAME TO members;

-- 重命名列
ALTER TABLE users RENAME COLUMN name TO full_name;

-- 重命名约束
ALTER TABLE users RENAME CONSTRAINT users_email_key TO unique_email;

3.4 删除列 #

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

-- 删除列及依赖
ALTER TABLE users DROP COLUMN phone CASCADE;

-- 条件删除
ALTER TABLE users DROP COLUMN IF EXISTS phone;

3.5 添加约束 #

sql
-- 添加主键
ALTER TABLE users ADD PRIMARY KEY (id);

-- 添加外键
ALTER TABLE posts 
    ADD CONSTRAINT fk_author 
    FOREIGN KEY (author_id) REFERENCES users(id);

-- 添加唯一约束
ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email);

-- 添加检查约束
ALTER TABLE products ADD CONSTRAINT positive_price CHECK (price > 0);

3.6 删除约束 #

sql
-- 删除约束
ALTER TABLE users DROP CONSTRAINT unique_email;

-- 条件删除
ALTER TABLE users DROP CONSTRAINT IF EXISTS unique_email;

四、删除表 #

4.1 删除表 #

sql
-- 删除表
DROP TABLE users;

-- 条件删除
DROP TABLE IF EXISTS users;

-- 级联删除
DROP TABLE users CASCADE;

4.2 清空表 #

sql
-- 清空表数据
TRUNCATE TABLE users;

-- 重置自增序列
TRUNCATE TABLE users RESTART IDENTITY;

-- 级联清空
TRUNCATE TABLE users CASCADE;

五、索引 #

5.1 创建索引 #

sql
-- 普通索引
CREATE INDEX idx_posts_author ON posts(author_id);

-- 复合索引
CREATE INDEX idx_posts_author_date ON posts(author_id, created_at DESC);

-- 唯一索引
CREATE UNIQUE INDEX idx_users_email ON users(email);

-- 部分索引
CREATE INDEX idx_active_users ON users(email) WHERE active = true;

-- 表达式索引
CREATE INDEX idx_lower_email ON users(LOWER(email));

-- GIN索引 (用于JSONB、数组)
CREATE INDEX idx_metadata ON products USING GIN (metadata);

-- 向量索引 (pgvector)
CREATE INDEX idx_embedding ON embeddings USING ivfflat (embedding vector_cosine_ops);

5.2 索引类型 #

类型 说明 适用场景
B-tree 默认类型 等值、范围查询
Hash 哈希索引 等值查询
GIN 通用倒排索引 JSONB、数组、全文搜索
GiST 通用搜索树 地理空间、范围
ivfflat 向量索引 向量相似度搜索

5.3 管理索引 #

sql
-- 查看表索引
SELECT * FROM pg_indexes WHERE tablename = 'posts';

-- 删除索引
DROP INDEX idx_posts_author;

-- 条件删除
DROP INDEX IF EXISTS idx_posts_author;

-- 重建索引
REINDEX INDEX idx_posts_author;
REINDEX TABLE posts;

六、使用客户端操作表 #

6.1 创建表 (迁移) #

bash
# 创建迁移文件
supabase migration new create_posts_table
sql
-- supabase/migrations/20240101000000_create_posts_table.sql
CREATE TABLE posts (
    id BIGSERIAL PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    title TEXT NOT NULL,
    content TEXT,
    author_id BIGINT REFERENCES users(id)
);

-- 启用RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- 创建策略
CREATE POLICY "Users can read own posts" ON posts
    FOR SELECT USING (author_id = auth.uid());
bash
# 应用迁移
supabase db push

6.2 查询表结构 #

typescript
// 获取表信息
const { data, error } = await supabase
  .from('posts')
  .select('*')
  .limit(1)

console.log('表结构:', Object.keys(data?.[0] || {}))

七、表设计最佳实践 #

7.1 命名规范 #

text
表名
├── 使用小写字母
├── 使用下划线分隔
├── 使用复数形式
└── 例如: users, posts, order_items

列名
├── 使用小写字母
├── 使用下划线分隔
├── 使用单数形式
└── 例如: user_id, created_at, is_active

外键
├── 格式: {table}_id
└── 例如: user_id, post_id

7.2 常用列设计 #

sql
-- 标准表模板
CREATE TABLE example (
    -- 主键
    id BIGSERIAL PRIMARY KEY,
    
    -- 时间戳
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    
    -- 软删除
    deleted_at TIMESTAMPTZ,
    
    -- 业务字段
    name TEXT NOT NULL,
    
    -- 外键
    user_id BIGINT REFERENCES users(id),
    
    -- 状态
    status TEXT DEFAULT 'active',
    
    -- 元数据
    metadata JSONB DEFAULT '{}'::jsonb
);

-- 自动更新updated_at触发器
CREATE TRIGGER set_updated_at
    BEFORE UPDATE ON example
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

7.3 性能考虑 #

text
设计原则
├── 合理使用索引
│   ├── 为查询条件创建索引
│   ├── 为排序字段创建索引
│   └── 避免过多索引
│
├── 选择合适的数据类型
│   ├── TEXT vs VARCHAR
│   ├── INTEGER vs BIGINT
│   └── JSONB vs JSON
│
├── 避免过度规范化
│   ├── 适当的冗余
│   └── 预计算统计
│
└── 分区大表
    ├── 按时间分区
    └── 按范围分区

八、常见表结构示例 #

8.1 用户资料表 #

sql
CREATE TABLE profiles (
    id UUID REFERENCES auth.users(id) PRIMARY KEY,
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    username TEXT UNIQUE,
    full_name TEXT,
    avatar_url TEXT,
    website TEXT,
    bio TEXT,
    
    CONSTRAINT username_length CHECK (char_length(username) >= 3)
);

-- 启用RLS
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Public profiles are viewable by everyone"
    ON profiles FOR SELECT USING (true);

CREATE POLICY "Users can insert own profile"
    ON profiles FOR INSERT WITH CHECK (auth.uid() = id);

CREATE POLICY "Users can update own profile"
    ON profiles FOR UPDATE USING (auth.uid() = id);

8.2 博客文章表 #

sql
CREATE TABLE posts (
    id BIGSERIAL PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    title TEXT NOT NULL,
    slug TEXT UNIQUE NOT NULL,
    content TEXT,
    excerpt TEXT,
    cover_image TEXT,
    published BOOLEAN DEFAULT FALSE,
    published_at TIMESTAMPTZ,
    author_id UUID REFERENCES auth.users(id) NOT NULL,
    view_count INTEGER DEFAULT 0,
    tags TEXT[] DEFAULT '{}',
    
    CONSTRAINT slug_format CHECK (slug ~ '^[a-z0-9-]+$')
);

-- 索引
CREATE INDEX idx_posts_author ON posts(author_id);
CREATE INDEX idx_posts_published ON posts(published, published_at DESC);
CREATE INDEX idx_posts_tags ON posts USING GIN (tags);

8.3 评论表 #

sql
CREATE TABLE comments (
    id BIGSERIAL PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    content TEXT NOT NULL,
    post_id BIGINT REFERENCES posts(id) ON DELETE CASCADE NOT NULL,
    user_id UUID REFERENCES auth.users(id) NOT NULL,
    parent_id BIGINT REFERENCES comments(id) ON DELETE CASCADE,
    
    CONSTRAINT content_length CHECK (char_length(content) >= 1 AND char_length(content) <= 10000)
);

-- 索引
CREATE INDEX idx_comments_post ON comments(post_id);
CREATE INDEX idx_comments_user ON comments(user_id);
CREATE INDEX idx_comments_parent ON comments(parent_id);

九、总结 #

表操作要点:

操作 SQL语句
创建表 CREATE TABLE
添加列 ALTER TABLE ADD COLUMN
修改列 ALTER TABLE ALTER COLUMN
删除列 ALTER TABLE DROP COLUMN
删除表 DROP TABLE
创建索引 CREATE INDEX

下一步,让我们学习数据类型!

最后更新:2026-03-28