Postgresql 删除后在远程数据库中插入行的触发器

Postgresql 删除后在远程数据库中插入行的触发器,postgresql,triggers,replication,plpgsql,dblink,Postgresql,Triggers,Replication,Plpgsql,Dblink,我创建了一个触发器,其工作原理如下: 从表flux\u tresorerie\u historique中删除数据后,将该行插入另一个数据库存档中的表flux\u tresorerie\u historique 我使用dblink在远程数据库中插入数据,问题是查询的创建太难,尤其是表包含20多列,我想为其他10个表创建类似的函数 是否有其他快速方法来确保这项任务 下面是一个很好的例子: CREATE OR REPLACE FUNCTION flux_tresorerie_historique_ba

我创建了一个触发器,其工作原理如下:
从表
flux\u tresorerie\u historique
中删除数据后,将该行插入另一个数据库存档中的表
flux\u tresorerie\u 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;

您可以为此使用
quote\u nullable
!另外,
concat\u 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;

请注意,可以在单引号之间放置非sting值,因为带引号的文字对于PostgreSQL来说与不带引号的文字值一样好,因此放置
quote\u nullable
处理的所有列都很方便。还请注意,
quote_nullable
将已经以YYYY-MM-DD格式输出日期(例如,
选择quote_nullable(now():date)
将导致
'2016-05-04'
),因此,您可能希望通过删除
to\u char

来进一步简化旧的.date\u relationment\u flux,这是一种有限的复制应用。需求千差万别,因此有许多不同的解决方案,针对不同的情况

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


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

  • 使用
    format()
    更优雅地转义字符串

  • 传递整行,而不是传递和转义每一列

  • 不要将密码放在每个触发器功能中。
    使用
    外部服务器
    用户映射
    。详细说明如下:

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

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');
最好不要以超级用户身份登录目标服务器。使用具有有限权限的专用角色以避免权限升级

并在目标服务器上使用,以允许无密码访问。这样,您甚至不必在
用户映射中存储密码。本相关答案最后一章中的说明:

然后:

如果行类型不匹配,则应该为目标表拼写列列表


如果你是认真的:

在表
flux\u tresorerie\u 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;
相关的:


我感谢您的回答,但我需要做的是通过从主服务器删除数据并将其重新插入备用服务器,将数据从主服务器存档到备用服务器,我使用了流复制,但问题是,当我从主服务器删除数据时,它会自动从备用服务器删除,请您推荐另一种解决我的问题的解决方案,这是本地表和远程表相同时的最佳解决方案,非常感谢
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;