You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL:约束table_data表的表列合法性并实现自动同步

PostgreSQL 表元数据校验与自动同步方案

首先修正原DDL的PostgreSQL兼容语法(PostgreSQL不支持auto_increment,使用标准的GENERATED ALWAYS AS IDENTITY):

CREATE TABLE table_data 
(
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    table_name VARCHAR(255) NOT NULL,
    column_name VARCHAR(255) NOT NULL,
    column_type VARCHAR(255),
    CONSTRAINT unique_table_column UNIQUE (table_name, column_name)
);

CREATE TABLE table1 
(
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    name VARCHAR(255) NOT NULL,
    username VARCHAR(255) NOT NULL
);

需求1:插入/更新时校验表与列存在性

PostgreSQL无法直接用CHECK约束查询系统表(CHECK不允许调用不稳定函数),因此使用触发器函数+行级触发器实现校验:

1. 创建校验触发器函数

CREATE OR REPLACE FUNCTION validate_table_column_exists()
RETURNS TRIGGER AS $$
BEGIN
    -- 校验目标表是否存在于当前模式
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.tables 
        WHERE table_schema = current_schema() 
          AND table_name = NEW.table_name
    ) THEN
        RAISE EXCEPTION '表 "%" 不存在于当前模式', NEW.table_name;
    END IF;

    -- 校验目标列是否存在于指定表
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns 
        WHERE table_schema = current_schema() 
          AND table_name = NEW.table_name 
          AND column_name = NEW.column_name
    ) THEN
        RAISE EXCEPTION '表 "%" 中不存在列 "%"', NEW.table_name, NEW.column_name;
    END IF;

    -- 自动填充列类型(可选,按需开启)
    SELECT data_type INTO NEW.column_type
    FROM information_schema.columns 
    WHERE table_schema = current_schema() 
      AND table_name = NEW.table_name 
      AND column_name = NEW.column_name;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

2. 绑定触发器到table_data

CREATE TRIGGER trigger_validate_table_column
BEFORE INSERT OR UPDATE ON table_data
FOR EACH ROW EXECUTE FUNCTION validate_table_column_exists();

测试示例

  • 合法插入(执行无错误):
    INSERT INTO table_data (table_name, column_name) VALUES ('table1', 'name');
    
  • 非法插入(触发错误):
    -- 表不存在的情况
    INSERT INTO table_data (table_name, column_name) VALUES ('invalid_table', 'col');
    -- 列不存在的情况
    INSERT INTO table_data (table_name, column_name) VALUES ('table1', 'invalid_col');
    

需求2:自动同步表元数据(删除列时删除对应行,自动插入/更新列信息)

使用事件触发器监控DDL操作,自动同步table_data的内容:

1. 创建同步事件触发器函数

CREATE OR REPLACE FUNCTION sync_table_data()
RETURNS EVENT_TRIGGER AS $$
DECLARE
    rec RECORD;
    target_table TEXT;
    target_column TEXT;
    col_type TEXT;
BEGIN
    -- 处理CREATE TABLE:插入新表的所有列
    IF tg_tag = 'CREATE TABLE' THEN
        SELECT objid::regclass INTO target_table FROM pg_event_trigger_ddl_commands();
        FOR rec IN 
            SELECT col.column_name, col.data_type
            FROM information_schema.columns col
            WHERE col.table_schema = current_schema() 
              AND col.table_name = target_table
        LOOP
            INSERT INTO table_data (table_name, column_name, column_type)
            VALUES (target_table, rec.column_name, rec.data_type)
            ON CONFLICT (table_name, column_name) DO UPDATE 
            SET column_type = EXCLUDED.column_type;
        END LOOP;
    END IF;

    -- 处理ALTER TABLE ADD COLUMN:插入新增列
    IF tg_tag = 'ALTER TABLE ADD COLUMN' THEN
        SELECT objid::regclass INTO target_table FROM pg_event_trigger_ddl_commands();
        SELECT arg INTO target_column FROM pg_event_trigger_ddl_commands();
        SELECT data_type INTO col_type
        FROM information_schema.columns 
        WHERE table_schema = current_schema() 
          AND table_name = target_table 
          AND column_name = target_column;
        
        INSERT INTO table_data (table_name, column_name, column_type)
        VALUES (target_table, target_column, col_type)
        ON CONFLICT (table_name, column_name) DO UPDATE 
        SET column_type = EXCLUDED.column_type;
    END IF;

    -- 处理ALTER TABLE DROP COLUMN:删除对应行
    IF tg_tag = 'ALTER TABLE DROP COLUMN' THEN
        SELECT objid::regclass INTO target_table FROM pg_event_trigger_ddl_commands();
        SELECT arg INTO target_column FROM pg_event_trigger_ddl_commands();
        
        DELETE FROM table_data
        WHERE table_name = target_table 
          AND column_name = target_column;
    END IF;

    -- 处理ALTER TABLE ALTER COLUMN:更新列类型
    IF tg_tag = 'ALTER TABLE ALTER COLUMN' THEN
        SELECT objid::regclass INTO target_table FROM pg_event_trigger_ddl_commands();
        SELECT arg INTO target_column FROM pg_event_trigger_ddl_commands();
        SELECT data_type INTO col_type
        FROM information_schema.columns 
        WHERE table_schema = current_schema() 
          AND table_name = target_table 
          AND column_name = target_column;
        
        UPDATE table_data
        SET column_type = col_type
        WHERE table_name = target_table 
          AND column_name = target_column;
    END IF;
END;
$$ LANGUAGE plpgsql;

2. 创建事件触发器

CREATE EVENT TRIGGER event_sync_table_data
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE', 'ALTER TABLE ADD COLUMN', 'ALTER TABLE DROP COLUMN', 'ALTER TABLE ALTER COLUMN')
EXECUTE FUNCTION sync_table_data();

测试示例

  • 创建新表:
    CREATE TABLE table2 (id INT, email VARCHAR(255));
    -- 自动将table2的id、email列插入table_data
    
  • 删除列:
    ALTER TABLE table1 DROP COLUMN username;
    -- 自动删除table_data中table1.username的对应行
    
  • 修改列类型:
    ALTER TABLE table2 ALTER COLUMN email TYPE TEXT;
    -- 自动更新table_data中table2.email的column_type为text
    

内容的提问来源于stack exchange,提问作者Ayan Dhara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:02:09