两表不在同一数据库之间的复制数据

本文提供了一个Oracle数据库中使用PL/SQL编写的示例脚本,该脚本通过游标遍历EMS_CUSTOMS_BROKER表中的记录,并根据每个客户的代码查询BLACK_CUSTOM_LOG表来获取进出黑名单的时间。然后,将这些信息连同客户的基本信息插入到目标表中。此外,还展示了如何处理客户别名数据及ID生成器的更新。

--依靠DBMS_OUTPUT.PUT_LINE导出的语句,再执行导出的语句

--SET SERVEROUTPUT ON;
DECLARE
 CURSOR customerCursor IS SELECT * FROM EMS_CUSTOMS_BROKER WHERE CUSTOM_FLAG = 'C'; 
 v_customer_pk       NUMBER;
 v_customer_rowCount NUMBER;
  v_in_bklst_time     DATE;
  v_out_bklst_time    DATE;
  v_in_bklst_time_str VARCHAR2(30);
  v_out_bklst_time_str VARCHAR2(30);
 v_customer EMS_CUSTOMS_BROKER%ROWTYPE;
 
  v_customerDtl_pk       NUMBER;
  v_customerDtl_rowCount NUMBER;
  v_customerDtl EMS_CUSTOMS_DETAIL%ROWTYPE;
 
BEGIN
  DBMS_OUTPUT.ENABLE(1000000);
  DBMS_OUTPUT.PUT_LINE('SET SERVEROUTPUT ON;');
 DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE(''start import customer broker data...'');');
 v_customer_pk := 1;
 v_customer_rowCount :=0;
 v_customerDtl_pk       :=1;
  v_customerDtl_rowCount := 0;
 
  OPEN customerCursor;
 LOOP
  FETCH customerCursor INTO v_customer;
  EXIT WHEN customerCursor%NOTFOUND;
   
    SELECT MAX(b.CREATE_DATETIME) INTO v_in_bklst_time FROM BLACK_CUSTOM_LOG b
            WHERE b.CUSTOM_CODE = v_customer.CUSTOM_CODE AND b.BLACK_FLAGE  = 'L';
             
    SELECT MAX(b.CREATE_DATETIME) INTO v_out_bklst_time FROM BLACK_CUSTOM_LOG b
            WHERE b.CUSTOM_CODE = v_customer.CUSTOM_CODE AND b.BLACK_FLAGE = 'R';
  
    IF v_in_bklst_time IS NOT NULL
    THEN v_in_bklst_time_str := to_char(v_in_bklst_time,'yyyy-MM-dd hh24:mi:ss');
    END IF;
   
    IF v_out_bklst_time IS NOT NULL
    THEN v_out_bklst_time_str := to_char(v_out_bklst_time,'yyyy-MM-dd hh24:mi:ss');
    END IF;
   
    DBMS_OUTPUT.PUT_LINE(
      'INSERT INTO MEMS_CUSTOMS_BROKER('||
      'ID, CODE, NAME, IS_IN_BLACK_LIST, '||
      'IN_BKLST_TIME, OUT_BKLST_TIME, '||
      'OWED_PAYMENT_BILL_COUNT, CREATED_BY, '||
      'CREATED_TIME, VERSION) '
    );
  DBMS_OUTPUT.PUT_LINE(
      'VALUES(' || v_customer_pk || ', ''' ||
      v_customer.CUSTOM_CODE || ''', ''' ||
      v_customer.CUSTOMS_BROKER || ''', '||
      CASE WHEN v_customer.BLACK_STATUS = 'Y' THEN 1 ELSE 0 END  || ', ' ||
      CASE WHEN v_customer.BLACK_STATUS = 'Y' AND v_in_bklst_time IS NOT NULL
           THEN 'TO_DATE('''||v_in_bklst_time_str||''',''yyyy-MM-dd hh24:mi:ss'')'
           ELSE 'NULL' END || ', ' ||
      CASE WHEN v_customer.BLACK_STATUS = 'N' AND v_out_bklst_time IS NOT NULL
           THEN 'TO_DATE('''||v_out_bklst_time_str||''',''yyyy-MM-dd hh24:mi:ss'')'
           ELSE 'NULL' END || ', ' ||
      '0, ''MEMSSYS'', sysdate, 0);'
  );
   
    DECLARE
      CURSOR customerDtlCursor IS SELECT * FROM EMS_CUSTOMS_DETAIL WHERE CUSTOM_CODE = v_customer.CUSTOM_CODE;
     
      BEGIN
      OPEN customerDtlCursor;
      LOOP
        FETCH customerDtlCursor INTO v_customerDtl;
        EXIT WHEN customerDtlCursor%NOTFOUND;
      
        DBMS_OUTPUT.PUT_LINE(
          'INSERT INTO MEMS_CUSTOMS_BROKER_ALIAS('||
          'ID ,BROKER_ALIAS ,CUSTOMS_BROKER_ID ,'||
          'CREATED_BY ,CREATED_TIME ,VERSION)'
        );
        DBMS_OUTPUT.PUT_LINE(
          'VALUES('|| v_customerDtl_pk || ', '''
          || v_customerDtl.CUSTOMS_BROKER || ''', '
          || v_customer_pk || ', ''MEMSSYS'', sysdate, 0);'
        );

        v_customerDtl_pk := v_customerDtl_pk + 1;
        v_customerDtl_rowCount := v_customerDtl_rowCount + 1 ;
      END LOOP;
      CLOSE customerDtlCursor;
      END;
   
  v_customer_pk := v_customer_pk + 1;
  v_customer_rowCount := v_customer_rowCount + 1;
   
 END LOOP;
 CLOSE customerCursor;
 
  DECLARE
    CURSOR customerDtlNoIdCursor IS SELECT * FROM EMS_CUSTOMS_DETAIL d
           WHERE d.CUSTOM_CODE NOT IN (SELECT CUSTOM_CODE FROM EMS_CUSTOMS_BROKER)
           OR d.CUSTOM_CODE IS NULL;
    BEGIN
    OPEN customerDtlNoIdCursor;
    LOOP
      FETCH customerDtlNoIdCursor INTO v_customerDtl;
      EXIT WHEN customerDtlNoIdCursor%NOTFOUND;
     
      DBMS_OUTPUT.PUT_LINE(
        'INSERT INTO MEMS_CUSTOMS_BROKER_ALIAS('||
        'ID ,BROKER_ALIAS ,'||
        'CREATED_BY ,CREATED_TIME ,VERSION)'
      );
      DBMS_OUTPUT.PUT_LINE(
        'VALUES('|| v_customerDtl_pk || ', '''
        || v_customerDtl.CUSTOMS_BROKER || ''', '
        || '''MEMSSYS'', sysdate, 0);'
      );

      v_customerDtl_pk := v_customerDtl_pk + 1;
      v_customerDtl_rowCount := v_customerDtl_rowCount + 1 ;
     
    END LOOP;
    CLOSE customerDtlNoIdCursor;
    END; 
 
  DBMS_OUTPUT.PUT_LINE(
  'INSERT INTO ID_GENERATOR(ID_KEY,ID_VALUE) VALUES(''CUSTOMS_BROKER_ALIAS_ID'' , '|| v_customerDtl_pk||');'
  );
 
  DBMS_OUTPUT.PUT_LINE(
  'INSERT INTO ID_GENERATOR(ID_KEY,ID_VALUE) VALUES(''CUSTOMS_BROKER_ID'' , ' || v_customer_pk || ');'
  );
 
  DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE(''import customer broker alias row count: '|| v_customerDtl_rowCount ||''');');
  DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE(''import customer broker row count: '|| v_customer_rowCount ||''');');
 DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE(''import customer broker end.'');');
 COMMIT;
 
 EXCEPTION
  WHEN OTHERS
  THEN
   DBMS_OUTPUT.PUT_LINE('import customer broker error:' || SQLERRM);
   ROLLBACK;
END ; 

<think>首先,用户的问题是关于在同一数据库系统中复制PostgreSQL数据库的方法。我需要参考提供的引用内容,并结合我的知识回答。 回顾引用内容: - 引用[1]、[2]、[3]讨论了PostgreSQL的复制特性,包括同步、异步、半同步复制,基于WAL日志。 - 引用[3]具体描述了同步流复制和如何处理从库宕机的情况。 - 引用[4]比较了PostgreSQL和MySQL的一些区别。 - 引用[5]提到了PostgreSQL的日常操作命令,如查看锁定。 用户的需求是“在同一数据库系统中复制pgsql数据库”,这意味着他们想在同一个PostgreSQL实例或多个实例之间复制数据库。这可能涉及到数据库复制克隆。 在PostgreSQL中,"复制数据库" 可以有几种含义: 1. **逻辑复制**:复制单个数据库的内容。 2. **物理复制**:复制整个数据库集群(所有数据库),通常通过流复制。 3. **克隆数据库**:创建数据库的副本,使用SQL命令如`CREATE DATABASE ... TEMPLATE ...`。 用户指定了"同一数据库系统",所以这可能指的是在同一个PostgreSQL实例中复制一个数据库,或者在多个实例之间,但系统指的是同一PostgreSQL安装或集群。 从引用中: - 引用[1]、[2]提到PostgreSQL支持同步、异步、半同步复制,基于WAL日志。 - 引用[3]讨论同步流复制。 这主要针对高可用性和复制到从服务器,而不是在同一实例内复制单个数据库。 对于一个实例内的复制,更常见的方法是使用`CREATE DATABASE`命令结合`TEMPLATE`选项。 标准方法是: - 使用SQL命令:`CREATE DATABASE newdb TEMPLATE olddb;` 这会在同一服务器上快速复制数据库。 如果用户指的是复制到另一个实例,则需要设置流复制或逻辑复制。 用户说“同一数据库系统”,我认为这指的是同一个PostgreSQL安装,所以在同一个实例内复制。 在回答中: - 我需要基于引用提供信息。 - 引用[5]提到了数据库操作命令,如查看锁定状态,这可能与复制过程相关。 - 引用[3]讨论了同步复制,但那是针对集群级别的。 结构化回答: 1. **介绍方法**:解释在同一PostgreSQL实例中复制数据库的方法。 2. **使用SQL命令**:推荐使用`CREATE DATABASE ... TEMPLATE ...`。 3. **注意事项**:确保源数据库没有被其他连接使用,避免锁定问题。 4. **其他选项**:如果需要复制到另一个实例,简要提及流复制或逻辑复制。 5. **参考引用**:自然地融入引用内容。 相关问题: - 根据系统指令,我需要生成相关问题。 - 问题应与主题相关。 最终回答在中文中。 步骤: 1. **确认方法**:主方法是SQL命令。 2. **细节**:描述命令语法和前提条件。 3. **警告**:复制时源数据库不能被使用。 4. **额外信息**:如果需要集群间复制,提到基于WAL的复制(引用[1]-[3])。 5. **生成问题**:如如何避免锁定问题、性能影响等。 命令示例: - `CREATE DATABASE new_db TEMPLATE existing_db;` 从引用[5],有查看锁定状态的命令,可以在复制前使用。 完整回答: - 开头:直接回答问题。 - 主体:分步骤解释。 - 结尾:相关问题。 </think>基于您的查询,我找到了在同一PostgreSQL数据库系统(即同一个PostgreSQL实例内)复制数据库的方法。PostgreSQL提供了内置命令来高效复制数据库,这通常用于创建数据库克隆(例如,用于测试、备份或开发环境)。以下是详细步骤和说明,参考了提供的引用内容并结合PostgreSQL的最佳实践。 ### 在同一PostgreSQL实例中复制数据库的方法 在同一个PostgreSQL系统中复制数据库,常用的方法是使用SQL命令`CREATE DATABASE`结合`TEMPLATE`选项。这个方法直接在服务器上创建一个新数据库,作为现有数据库的副本。以下是逐步指南: 1. **基本命令语法**: ```sql CREATE DATABASE new_db_name TEMPLATE existing_db_name; ``` - `new_db_name`:您要创建的新数据库名称。 - `existing_db_name`:被复制的源数据库名称。 - 这个命令会复制数据库的所有对象(如、索引、函数和数据),但不会复制角色或配置设置。 2. **前提条件**: - 确保源数据库(`existing_db_name`)**没有活跃连接**。PostgreSQL在复制数据库时要求源数据库处于空闲状态,否则会发生锁定问题(例如,如果其他用户或进程正在访问数据库复制操作会失败或阻塞)[^5]。 - 您需要具有`CREATEDB`权限(例如,以超级用户或数据库所有者身份执行命令)。 - 在复制前,建议检查数据库锁定状态,以避免冲突。可以使用以下命令(参考引用[5]): ```sql SELECT pg_class.relname AS table, pg_database.datname AS database, pid, mode, granted FROM pg_locks, pg_class, pg_database WHERE pg_locks.relation = pg_class.oid AND pg_locks.database = pg_database.oid; ``` 如果查询结果显示源数据库有锁定(`mode`列为`AccessExclusiveLock`),则应断开相关连接后再执行复制。 3. **操作步骤示例**: - **连接到PostgreSQL**:使用`psql`命令行工具或其他客户端登录到数据库。 ```bash psql -U your_username -d postgres ``` - **执行复制命令**: ```sql CREATE DATABASE my_new_db TEMPLATE my_old_db; ``` - 此操作会快速完成(速度取决于数据库大小),因为它本质上是文件级别的复制(基于底层WAL机制,确保数据一致性)[^1]。 - **验证复制结果**: ```sql \l -- 列出所有数据库,检查新数据库是否创建成功 \c my_new_db -- 连接到新数据库 \dt -- 显示,确认数据复制 ``` 4. **优点和注意事项**: - **优点**: - **高效快速**:由于PostgreSQL使用WAL(Write-Ahead Logging)机制作为基础,复制过程是原子的,不会中断服务(对于只读或空闲数据库)[^1][^2]。 - **数据一致性**:新数据库是源数据库的精确副本,适用于备份或迁移测试。 - **注意事项**: - **锁定问题**:如果源数据库有活跃会话,命令会失败(抛出错误如`source database is being accessed by other users`)。在复制前,使用`pg_terminate_backend(pid)`命令终止连接或安排在低峰期操作。 - **存储空间**:确保磁盘空间足够,新数据库会占用与源数据库相似的容量。 - **模板数据库**:默认情况下,`template1`是PostgreSQL的模板数据库,您可以自定义模板(例如,`CREATE DATABASE ... TEMPLATE template0;`),但直接复制用户数据库更简单。 - **不支持实时复制**:这个方法创建的是静态副本,而不是实时同步。如果需要实时复制(如高可用场景),应使用PostgreSQL的流复制机制(基于WAL),但这通常涉及多个实例(而非同一系统内),参考引用[3]中提到的同步流复制[^3]。 5. **其他方法比较**: - **逻辑导出/导入**:使用`pg_dump`和`pg_restore`命令可以导出数据库为逻辑备份文件,然后在同一服务器上导入为新数据库。这更灵活(支持部分复制),但速度较慢: ```bash pg_dump existing_db_name > dump.sql createdb new_db_name psql new_db_name < dump.sql ``` - **文件系统级复制**:直接复制PostgreSQL的数据目录(`/var/lib/pgsql/data/base/`),但不推荐,因为容易导致数据不一致(需要停止服务)[^1]。 ### 总结 - **推荐方法**:在同一PostgreSQL实例内,使用`CREATE DATABASE ... TEMPLATE ...`命令是最简单、最高效的复制方法。它利用了PostgreSQL的底层WAL机制,确保副本完整性[^1][^2]。 - **适用场景**:适用于开发环境测试、数据备份或快速克隆数据库。如果您的需求扩展到跨实例的实时复制(如高可用),PostgreSQL支持同步流复制(基于WAL),但这需要配置集群设置(参考引用[3])[^3]。 如果您在操作中遇到锁定问题或其他错误,请参考引用[5]的锁定查询命令进行诊断[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值