【问题标题】:Trigger to insert rows in remote database after deletion删除后触发在远程数据库中插入行
【发布时间】:2016-05-03 18:25:07
【问题描述】:

我创建了一个像这样工作的触发器:
从表flux_tresorerie_historique 中删除数据后,它将这一行插入到位于另一个数据库存档中的表flux_tresorerie_historique

我使用dblink在远程数据库中插入数据,问题是创建查询太难了特别是表包含超过20列,我想为其他10个表创建类似的功能。

还有其他快速的方法来确保这项任务吗?

这是一个很好的例子:

CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
RETURNS trigger AS
$BODY$
DECLARE date_rapprochement_flux TEXT;
DECLARE code_commission  TEXT;
DECLARE reference_flux TEXT;
BEGIN
IF OLD.date_rapprochement_flux is null
THEN
date_rapprochement_flux = 'NULL';
ELSE
date_rapprochement_flux = ''''||to_char(OLD.date_rapprochement_flux, 'YYYY-MM-DD')||'''';
END IF;

IF OLD.code_commission is null
THEN
code_commission = 'NULL';
ELSE
code_commission = ''''||replace(OLD.code_commission,'''','''''')||'''';
END IF;

IF OLD.reference_flux is null
THEN
reference_flux = 'NULL';
ELSE
reference_flux = ''''||replace(OLD.reference_flux,'''','''''')||'''';
END IF;

perform dblink_connect('dbname=gtr_bd_archive user=postgres     password=postgres');
perform dblink_exec('insert into flux_tresorerie_historique values('||OLD.id_flux_historique||','''||OLD.date_operation_flux||''','''||OLD.date_valeur_flux||''','||date_rapprochement_flux||','''||replace(OLD.libelle_flux,'''','''''')||''','||OLD.montant_flux||','||OLD.contre_valeur_dzd||','''||replace(OLD.rib_compte_bancaire,'''','''''')||''','||OLD.frais_flux||','''||replace(OLD.sens_flux,'''','''''')||''','''||replace(OLD.statut_flux,'''','''''')||''','''||replace(OLD.code_devise,'''','''''')||''','''||replace(OLD.code_mode_paiement,'''','''''')||''','''||replace(OLD.code_agence,'''','''''')||''','''||replace(OLD.code_compte,'''','''''')||''','''||replace(OLD.code_banque,'''','''''')||''','''||OLD.date_maj_flux||''','''||replace(OLD.statut_frais,'''','''''')||''','||reference_flux||','||code_commission||','||OLD.id_flux||');');
perform dblink_disconnect();
RETURN NULL;
END;

【问题讨论】:

    标签: postgresql triggers replication plpgsql dblink


    【解决方案1】:

    这是复制的有限应用。需求变化很大,因此有许多不同的既定解决方案,可以解决不同的情况。 Consider the overview in the manual.

    您的手工编织、基于触发器的解决方案是相对少数删除的可行选择。为每一行打开和关闭一个单独的连接会产生相当大的开销。还有其他各种选择。


    在使用 dblink 时我建议进行一些修改。最重要的是:

    基本上,在源服务器上运行一次

    CREATE SERVER myserver FOREIGN DATA WRAPPER dblink_fdw
    OPTIONS (hostaddr '127.0.0.1', dbname 'gtr_bd_archive');
    
    CREATE USER MAPPING FOR role_source SERVER myserver
    OPTIONS (user 'postgres', password 'secret');
    

    最好不要在目标服务器上以超级用户身份登录。使用具有有限权限的专用角色以避免权限提升。

    并在目标服务器上使用password file 以允许无密码访问。这样您甚至不必将密码存储在USER MAPPING 中。此相关答案最后一章的说明:

    然后:

    CREATE OR REPLACE FUNCTION pg_temp.flux_tresorerie_historique_backup_row()
      RETURNS trigger AS
    $func$
    BEGIN
       PERFORM dblink_connect('myserver');  -- name of foreign server from above
    
       PERFORM dblink_exec( format(
       $$
       INSERT INTO flux_tresorerie_historique  -- provide target column list!
       SELECT (r).id_flux_historique
            , (r).date_operation_flux
            , (r).date_valeur_flux
            , (r).date_rapprochement_flux::date  -- 'YYYY-MM-DD' is default ISO format anyway
            , (r).libelle_flux
            , (r).montant_flux
            , (r).contre_valeur_dzd
            , (r).rib_compte_bancaire
            , (r).frais_flux
            , (r).sens_flux
            , (r).statut_flux
            , (r).code_devise
            , (r).code_mode_paiement
            , (r).code_agence
            , (r).code_compte
            , (r).code_banque
            , (r).date_maj_flux
            , (r).statut_frais
            , (r).reference_flux
            , (r).code_commission
            , (r).id_flux
       FROM   (SELECT %L::flux_tresorerie_historique) t(r)
       $$, OLD::text));  -- cast whole row type
    
       PERFORM dblink_disconnect();
       RETURN NULL;  -- only for AFTER trigger
    END
    $func$  LANGUAGE plpgsql;
    

    如果行类型不匹配,您应该拼出目标表的列列表。


    如果你是认真的:

    在表格flux_tresorerie_historique中插入这一行

    即,您插入 整行 并且目标行类型相同(不从时间戳中提取日期等),您可以进一步简化传递整行。

    CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
      RETURNS trigger AS
    $func$
    BEGIN
       PERFORM dblink_connect('myserver');  -- name of foreign server
    
       PERFORM dblink_exec( format(
       $$
       INSERT INTO flux_tresorerie_historique
       SELECT (%L::flux_tresorerie_historique).*
       $$
       , OLD::text));
    
       PERFORM dblink_disconnect();
       RETURN NULL;  -- only for AFTER trigger
    END
    $func$  LANGUAGE plpgsql;
    

    相关:

    【讨论】:

    • 感谢您的回答,但我需要做的是通过从主服务器删除数据并将它们重新插入备用服务器,将数据从主服务器归档到备用服务器,我使用了流复制,但问题是当我从master中删除数据它会从standby中自动删除,请您提出另一种可以解决我的问题的解决方案
    • 这是本地和远程表相同时的最佳方案,非常感谢
    【解决方案2】:

    您可以为此使用quote_nullable!另外,concat_ws 非常方便:

    CREATE OR REPLACE FUNCTION flux_tresorerie_historique_backup_row()
    RETURNS trigger AS
    $BODY$
    BEGIN
      perform dblink_connect('dbname=gtr_bd_archive user=postgres password=postgres');
      perform dblink_exec('insert into flux_tresorerie_historique values('||
        concat_ws(', ', quote_nullable(OLD.id_flux_historique),
                        quote_nullable(OLD.date_operation_flux),
                        quote_nullable(OLD.date_valeur_flux),
                        quote_nullable(to_char(OLD.date_rapprochement_flux, 'YYYY-MM-DD')),
                        quote_nullable(OLD.libelle_flux),
                        quote_nullable(OLD.montant_flux),
                        quote_nullable(OLD.contre_valeur_dzd),
                        quote_nullable(OLD.rib_compte_bancaire),
                        quote_nullable(OLD.frais_flux),
                        quote_nullable(OLD.sens_flux),
                        quote_nullable(OLD.statut_flux),
                        quote_nullable(OLD.code_devise),
                        quote_nullable(OLD.code_mode_paiement),
                        quote_nullable(OLD.code_agence),
                        quote_nullable(OLD.code_compte),
                        quote_nullable(OLD.code_banque),
                        quote_nullable(OLD.date_maj_flux),
                        quote_nullable(OLD.statut_frais),
                        quote_nullable(OLD.reference_flux),
                        quote_nullable(OLD.code_commission),
                        quote_nullable(OLD.id_flux)
               )||');');
      perform dblink_disconnect();
      RETURN NULL;
    END;
    

    请注意,可以在单引号之间放置非字符串值,因为带引号的文字对于 PostgreSQL 来说与不带引号的文字值一样好,因此放置 @ 处理的所有列很方便987654324@。另请注意,quote_nullable 已经以 YYYY-MM-DD 格式输出日期(例如,select quote_nullable(now()::date) 将导致 '2016-05-04'),因此您可能希望通过删除 to_char 来进一步简化 OLD.date_rapprochement_flux

    【讨论】:

      猜你喜欢
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-27
      • 2012-10-06
      • 2014-07-07
      相关资源
      最近更新 更多