Postgres 14下为已有数据的tag表添加必填slug字段的SQL咨询
Postgres 14 为已有数据的tag表添加必填slug字段的正确实现
步骤1:添加可空的slug列
先给表新增允许为空的slug字段,避免直接添加非空约束导致已有数据校验失败:
ALTER TABLE tag ADD COLUMN slug VARCHAR;
步骤2:批量生成并更新slug值(覆盖全场景处理)
针对name字段做标准化处理:转小写、移除所有非字母数字标点、空格替换为连字符,同时处理连续特殊字符和首尾连字符的问题,用Postgres字符串函数组合实现:
UPDATE tag SET slug = TRIM( '-' FROM REGEXP_REPLACE( LOWER(name), '[^a-z0-9]+', -- 匹配所有非字母数字的连续字符(含空格、标点) '-', -- 将匹配到的内容替换为单个连字符 'g' -- 全局替换,处理所有匹配项 ) );
如果需要避免slug重复(比如不同name处理后生成相同slug),可以给重复项添加序号后缀:
UPDATE tag t SET slug = CONCAT( sub.base_slug, CASE WHEN sub.count > 1 THEN '-' || sub.row_num ELSE '' END ) FROM ( SELECT id, TRIM('-' FROM REGEXP_REPLACE(LOWER(name), '[^a-z0-9]+', '-', 'g')) AS base_slug, COUNT(*) OVER (PARTITION BY TRIM('-' FROM REGEXP_REPLACE(LOWER(name), '[^a-z0-9]+', '-', 'g'))) AS count, ROW_NUMBER() OVER (PARTITION BY TRIM('-' FROM REGEXP_REPLACE(LOWER(name), '[^a-z0-9]+', '-', 'g')) ORDER BY id) AS row_num FROM tag ) AS sub WHERE t.id = sub.id;
这个版本会给重复slug自动追加序号,比如java、java-1、java-2,避免后续加唯一约束时冲突。
步骤3:设置slug字段为非空约束
确认所有行的slug都已成功填充后,修改字段属性为非空:
ALTER TABLE tag ALTER COLUMN slug SET NOT NULL;
关于FOR EACH的疑问
你不需要用FOR EACH,普通UPDATE语句默认会作用于表中所有行(无WHERE条件时)。FOR EACH是触发器场景下的语法,比如后续要实现"新增/修改name时自动更新slug"的逻辑,才需要在触发器函数中使用FOR EACH ROW。本次是一次性迁移已有数据,直接用上述UPDATE语句即可。
内容的提问来源于stack exchange,提问作者Filip Stojavonic
相关产品推荐
相关产品推荐

