Supabase数据更新 #
一、基础更新 #
1.1 使用SQL更新 #
sql
-- 更新单条记录
UPDATE users
SET name = 'John Updated'
WHERE id = 1;
-- 更新多个字段
UPDATE users
SET
name = 'John Doe',
email = 'john.doe@example.com',
updated_at = NOW()
WHERE id = 1;
-- 更新并返回
UPDATE users
SET name = 'John Updated'
WHERE id = 1
RETURNING *;
1.2 使用客户端更新 #
typescript
// 更新单条记录
const { data, error } = await supabase
.from('users')
.update({ name: 'John Updated' })
.eq('id', 1)
.select()
// 更新多个字段
const { data, error } = await supabase
.from('users')
.update({
name: 'John Doe',
email: 'john.doe@example.com',
updated_at: new Date().toISOString()
})
.eq('id', 1)
.select()
1.3 更新注意事项 #
text
重要提示
├── update()必须配合过滤条件使用
├── 默认更新所有匹配的记录
├── 建议使用.eq('id', xxx)限制范围
└── 使用.select()返回更新后的数据
二、条件更新 #
2.1 各种过滤条件 #
typescript
// 按ID更新
const { data } = await supabase
.from('products')
.update({ price: 99.99 })
.eq('id', 1)
// 按多个条件更新
const { data } = await supabase
.from('products')
.update({ status: 'sold' })
.eq('category', 'electronics')
.lt('stock', 1)
// 更新特定用户的数据
const { data } = await supabase
.from('posts')
.update({ published: true })
.eq('author_id', userId)
.eq('id', postId)
2.2 SQL条件更新 #
sql
-- 多条件更新
UPDATE products
SET status = 'out_of_stock'
WHERE category = 'electronics' AND stock = 0;
-- 使用子查询更新
UPDATE products
SET featured = true
WHERE id IN (
SELECT product_id
FROM order_items
GROUP BY product_id
HAVING COUNT(*) > 100
);
-- 使用CASE更新
UPDATE products
SET price = CASE
WHEN category = 'electronics' THEN price * 0.9
WHEN category = 'books' THEN price * 0.8
ELSE price
END;
三、批量更新 #
3.1 客户端批量更新 #
typescript
// 更新所有匹配的记录
const { data, error } = await supabase
.from('products')
.update({ on_sale: true })
.eq('category', 'electronics')
// 批量更新特定记录
const { data, error } = await supabase
.from('products')
.update({ status: 'archived' })
.in('id', [1, 2, 3, 4, 5])
3.2 SQL批量更新 #
sql
-- 批量更新
UPDATE products
SET discount = 0.1
WHERE category IN ('electronics', 'books');
-- 从另一个表更新
UPDATE products p
SET stock = i.new_stock
FROM inventory i
WHERE p.id = i.product_id;
四、增量更新 #
4.1 数值增减 #
typescript
// 使用RPC进行增量更新
const { data, error } = await supabase.rpc('increment_view_count', {
post_id: 1
})
sql
-- 创建增量函数
CREATE OR REPLACE FUNCTION increment_view_count(post_id BIGINT)
RETURNS VOID AS $$
BEGIN
UPDATE posts
SET view_count = view_count + 1
WHERE id = post_id;
END;
$$ LANGUAGE plpgsql;
-- 创建通用增量函数
CREATE OR REPLACE FUNCTION increment_column(
table_name TEXT,
column_name TEXT,
row_id BIGINT,
increment_value NUMERIC DEFAULT 1
)
RETURNS VOID AS $$
BEGIN
EXECUTE format(
'UPDATE %I SET %I = %I + $1 WHERE id = $2',
table_name, column_name, column_name
)
USING increment_value, row_id;
END;
$$ LANGUAGE plpgsql;
4.2 SQL增量更新 #
sql
-- 增加数值
UPDATE products
SET stock = stock + 10
WHERE id = 1;
-- 减少数值
UPDATE products
SET stock = stock - 1
WHERE id = 1 AND stock > 0;
-- 返回更新后的值
UPDATE products
SET view_count = view_count + 1
WHERE id = 1
RETURNING view_count;
五、JSON更新 #
5.1 更新整个JSON字段 #
typescript
// 替换整个JSON
const { data, error } = await supabase
.from('products')
.update({
metadata: {
color: 'red',
size: 'large',
weight: 2.5
}
})
.eq('id', 1)
5.2 更新JSON部分字段 #
sql
-- 更新JSON中的特定字段
UPDATE products
SET metadata = jsonb_set(metadata, '{color}', '"blue"')
WHERE id = 1;
-- 添加新字段
UPDATE products
SET metadata = metadata || '{"brand": "Apple"}'::jsonb
WHERE id = 1;
-- 删除字段
UPDATE products
SET metadata = metadata - 'weight'
WHERE id = 1;
-- 更新嵌套字段
UPDATE products
SET metadata = jsonb_set(metadata, '{specs,ram}', '32'::jsonb)
WHERE id = 1;
5.3 使用RPC更新JSON #
sql
-- 创建JSON更新函数
CREATE OR REPLACE FUNCTION update_product_metadata(
product_id BIGINT,
new_metadata JSONB
)
RETURNS VOID AS $$
BEGIN
UPDATE products
SET metadata = metadata || new_metadata
WHERE id = product_id;
END;
$$ LANGUAGE plpgsql;
typescript
// 调用函数更新JSON
const { error } = await supabase.rpc('update_product_metadata', {
product_id: 1,
new_metadata: { color: 'green', featured: true }
})
六、数组更新 #
6.1 更新整个数组 #
typescript
// 替换整个数组
const { data, error } = await supabase
.from('posts')
.update({
tags: ['javascript', 'typescript', 'react']
})
.eq('id', 1)
6.2 SQL数组操作 #
sql
-- 添加元素
UPDATE posts
SET tags = array_append(tags, 'new-tag')
WHERE id = 1;
-- 删除元素
UPDATE posts
SET tags = array_remove(tags, 'old-tag')
WHERE id = 1;
-- 替换元素
UPDATE posts
SET tags = array_replace(tags, 'old-tag', 'new-tag')
WHERE id = 1;
-- 连接数组
UPDATE posts
SET tags = tags || ARRAY['tag1', 'tag2']
WHERE id = 1;
七、条件表达式更新 #
7.1 CASE表达式 #
sql
-- 条件更新
UPDATE products
SET status = CASE
WHEN stock = 0 THEN 'out_of_stock'
WHEN stock < 10 THEN 'low_stock'
ELSE 'in_stock'
END;
-- 带条件的价格调整
UPDATE products
SET price = CASE
WHEN category = 'electronics' THEN price * 0.9
WHEN category = 'books' THEN price * 0.8
WHEN category = 'clothing' THEN price * 0.7
ELSE price
END;
7.2 COALESCE更新 #
sql
-- 使用COALESCE处理NULL
UPDATE users
SET
name = COALESCE(name, 'Anonymous'),
avatar_url = COALESCE(avatar_url, '/default-avatar.png');
-- 使用NULLIF
UPDATE products
SET discount = NULLIF(discount, 0);
八、更新时间戳 #
8.1 自动更新时间戳 #
sql
-- 创建触发器函数
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
8.2 手动更新时间戳 #
typescript
// 更新时设置时间戳
const { data, error } = await supabase
.from('users')
.update({
name: 'John Updated',
updated_at: new Date().toISOString()
})
.eq('id', 1)
九、软删除 #
9.1 实现软删除 #
typescript
// 软删除
const { data, error } = await supabase
.from('users')
.update({
deleted_at: new Date().toISOString(),
status: 'deleted'
})
.eq('id', 1)
9.2 恢复软删除 #
typescript
// 恢复
const { data, error } = await supabase
.from('users')
.update({
deleted_at: null,
status: 'active'
})
.eq('id', 1)
9.3 查询时排除软删除 #
typescript
// 使用视图
const { data } = await supabase
.from('active_users') -- 视图
.select('*')
// 或在查询中过滤
const { data } = await supabase
.from('users')
.select('*')
.is('deleted_at', null)
十、并发控制 #
10.1 乐观锁 #
sql
-- 添加版本字段
ALTER TABLE products ADD COLUMN version INTEGER DEFAULT 1;
-- 更新时检查版本
UPDATE products
SET
price = 99.99,
version = version + 1
WHERE id = 1 AND version = 5;
-- 如果返回0行,说明版本不匹配
10.2 客户端乐观锁 #
typescript
async function updateWithVersion(
table: string,
id: number,
updates: any,
expectedVersion: number
) {
const { data, error } = await supabase
.from(table)
.update({
...updates,
version: expectedVersion + 1
})
.eq('id', id)
.eq('version', expectedVersion)
.select()
if (!data?.length) {
throw new Error('Version conflict - data may have been modified')
}
return data[0]
}
十一、错误处理 #
11.1 常见错误 #
typescript
const { data, error } = await supabase
.from('products')
.update({ price: -10 })
.eq('id', 1)
if (error) {
switch (error.code) {
case '23514':
console.error('违反检查约束')
break
case '23505':
console.error('唯一约束违反')
break
case '23503':
console.error('外键约束违反')
break
case '42501':
console.error('权限不足')
break
case 'PGRST116':
console.error('未找到匹配记录')
break
default:
console.error('更新失败:', error.message)
}
}
十二、实战示例 #
12.1 更新用户资料 #
typescript
async function updateProfile(
userId: string,
updates: { name?: string; bio?: string; avatar_url?: string }
) {
const { data, error } = await supabase
.from('profiles')
.update({
...updates,
updated_at: new Date().toISOString()
})
.eq('id', userId)
.select()
.single()
if (error) throw error
return data
}
12.2 更新产品库存 #
typescript
async function updateStock(productId: number, quantity: number) {
// 使用事务确保原子性
const { data, error } = await supabase.rpc('update_product_stock', {
product_id: productId,
quantity_change: quantity
})
if (error) throw error
return data
}
sql
CREATE OR REPLACE FUNCTION update_product_stock(
product_id BIGINT,
quantity_change INTEGER
)
RETURNS JSON AS $$
DECLARE
new_stock INTEGER;
BEGIN
UPDATE products
SET stock = stock + quantity_change
WHERE id = product_id
RETURNING stock INTO new_stock;
IF new_stock < 0 THEN
RAISE EXCEPTION 'Insufficient stock';
END IF;
RETURN json_build_object(
'product_id', product_id,
'new_stock', new_stock
);
END;
$$ LANGUAGE plpgsql;
12.3 批量更新状态 #
typescript
async function batchUpdateStatus(
productIds: number[],
newStatus: string
) {
const { data, error } = await supabase
.from('products')
.update({
status: newStatus,
updated_at: new Date().toISOString()
})
.in('id', productIds)
.select()
if (error) throw error
return data
}
十三、总结 #
更新操作要点:
| 操作 | 方法 |
|---|---|
| 基础更新 | update({…}).eq(‘id’, x) |
| 批量更新 | update({…}).in(‘id’, […]) |
| 条件更新 | update({…}).eq(…).gt(…) |
| JSON更新 | jsonb_set(), || 操作符 |
| 数组更新 | array_append(), array_remove() |
| 增量更新 | RPC函数 |
下一步,让我们学习数据删除!
最后更新:2026-03-28