Oracle 在表之间交换/移动分区

Oracle 在表之间交换/移动分区,oracle,partitioning,Oracle,Partitioning,我将此表作为我的主表: create table prova_log( id_dispositive number, type number, date_verification date, status number ) partition by range (date_verification) interval (NUMTODSINTERVAL(3,'DAY

我将此表作为我的主表:

create table prova_log(
       id_dispositive       number,
       type                 number,
       date_verification    date,
       status               number
)
partition by range (date_verification) interval (NUMTODSINTERVAL(3,'DAY'))
subpartition by list (type)  
subpartition TEMPLATE (
    SUBPARTITION type1 VALUES (1),
    SUBPARTITION type2 VALUES (2),
    SUBPARTITION type3 VALUES (3),
    SUBPARTITION type4 VALUES (4)
)                          
(
   partition p0816 values less than (to_date('01/09/2016','dd/mm/yyyy'))
);
我想用较旧的值进行某种备份,因此我创建了以下0行:

create table prova_log_old (
       id_dispositive       number,
       type                 number,
       date_verification    date,
       status               number
)
partition by range (date_verification) interval (NUMTODSINTERVAL(3,'DAY'))
subpartition by list (type)  
subpartition TEMPLATE (
    SUBPARTITION type1 VALUES (1),
    SUBPARTITION type2 VALUES (2),
    SUBPARTITION type3 VALUES (3),
    SUBPARTITION type4 VALUES (4)
)                          
(
   partition p_old values less than (to_date('01/09/2016','dd/mm/yyyy'))
);
所以我想移动/复制/交换15天以上的旧分区,以证明它是旧的

为此,我创建了以下工作:

PROCEDURE move_data_from_huge_table
   IS
      -- This will move all data after 'vcountdaystokeepdata' days
      vcountdaystokeepdata        NUMBER := 15;
      vcountdatainsidepartition   NUMBER := 0;
   BEGIN
      FOR item IN
         (SELECT *
            FROM (SELECT partition_name,
                         TO_DATE
                            (TRIM
                                ('''' FROM REGEXP_SUBSTR
                                             (EXTRACTVALUE
                                                 (DBMS_XMLGEN.getxmltype
                                                     (   'select high_value from all_tab_partitions where table_name='''
                                                      || table_name
                                                      || ''' and table_owner = '''
                                                      || table_owner
                                                      || ''' and partition_name = '''
                                                      || partition_name
                                                      || ''''
                                                     ),
                                                  '//text()'
                                                 ),
                                              '''.*?'''
                                             )
                                ),
                             'syyyy-mm-dd hh24:mi:ss'
                            ) high_value
                    FROM all_tab_partitions
                   WHERE table_name = 'PROVA_LOG')
           WHERE high_value < SYSDATE - vcountdaystokeepdata)
      LOOP                 
         EXECUTE IMMEDIATE    'alter table PROVA_LOG EXCHANGE PARTITION '
                           || item.partition_name
                           || ' with table PROVA_LOG_OLD';

         EXECUTE IMMEDIATE    'select count(*) from PROVA_LOG partition ('
                           || item.partition_name
                           || ')'
                      INTO vcountdatainsidepartition;

         IF vcountdatainsidepartition = 0
         THEN
            EXECUTE IMMEDIATE    'ALTER TABLE PROVA_LOG DROP PARTITION '
                              || item.partition_name
                              || '';
         END IF;

      END LOOP;
   END;
但当我运行程序时,我得到了

表的ORA-14292分区类型必须与复合分区的子分区类型匹配

我假设备份表中必须有一个与主分区表同名的分区,对吗

我怎样才能做到这一点


我试图将分区添加到备份表中,但没有成功。必须指出的是,所有分区的名称都是由oracle随机生成的。

我仍然不明白您为什么要移动分区,反正我有一个解决方案

首先,您可以对分区进行如下寻址

SELECT COUNT(*) FROM PROVA_LOG PARTITION (SYS_P7138);
或者你可以按你的意愿去做

SELECT COUNT(*) FROM PROVA_LOG PARTITION FOR (TO_DATE('2016-10-01', 'YYYY-MM-DD'));
或者如果您更喜欢日期文字

您的问题的自动解决方案可以是:

DECLARE

    CURSOR TabPartitions IS
    SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
    FROM USER_TAB_PARTITIONS 
    WHERE TABLE_NAME = 'PROVA_LOG'
    ORDER BY 1,2;

    ts DATE;

BEGIN
    FOR aPart IN TabPartitions LOOP
        EXECUTE IMMEDIATE 'BEGIN :ret := '||aPart.HIGH_VALUE||'; END;' USING OUT ts;
        IF ts <> DATE '2016-09-10' AND ts < SYSDATE - 15 THEN
            --EXECUTE IMMEDIATE 'INSERT INTO PROVA_LOG_OLD SELECT * FROM PROVA_LOG PARTITION FOR (DATE '''||TO_CHAR(ts, 'yyyy-mm-dd')||''')'; 
            --EXECUTE IMMEDIATE 'ALTER TABLE PROVA_LOG DROP PARTITION FOR (DATE '''||TO_CHAR(ts, 'yyyy-mm-dd')||''') UPDATE GLOBAL INDEXES';
            EXECUTE IMMEDIATE 'ALTER TABLE PROVA_LOG EXCHANGE PARTITION FOR (DATE '''||TO_CHAR(ts, 'yyyy-mm-dd')||''') WITH TABLE PROVA_LOG_OLD INCLUDING INDEXES';
        END IF;
    END LOOP;

END;
或者根本没有分区

CREATE TABLE prova_log_old (
       id_dispositive       NUMBER,
       TYPE                 NUMBER,
       date_verification    DATE,
       status               NUMBER
);

你做错了。您可以使用所有分区表交换分区,而不是使用it分区,只需再查看一次代码

 EXECUTE IMMEDIATE    'alter table PROVA_LOG EXCHANGE PARTITION '
                           || item.partition_name
                           || ' with table PROVA_LOG_OLD';
在exchange分区的情况下,您应该执行以下操作

创建没有分区的空表,其结构与PROVA_LOG相同,但未分区

使用新的_表交换生产表中的分区

将hist表中的分区与新的_表交换


为什么要将数据复制/移动到另一个表?分区表的主要好处之一是您不需要这些东西。@WernfriedDomscheit因为我还有另一项工作,可以按日期范围计算这数百万行。即使是分区的,当表的行数超过500M时,该过程也会花费太长时间。。。无论如何。。。我想在不失去老瓦勒斯的情况下放弃,因为我不再需要它们了。嘿,伙计,谢谢你的回答。。但是我觉得这很贵。。我的意思是每个分区至少有10万行。。。这将需要很长时间来执行,对吗?现在我在alter table exchange分区中得到了一个ORA-14128外键约束不匹配问题,我对它进行了测试,它对我来说是有效的。您是否按照提供的方式创建了新表prova\u log\u old?是的。。。正如你所说,我创建了“按列表分区”。但我的主桌有一些FK…这似乎是个问题。例如,您不能运行TRUNCATE TABLE。。。如果你有外键。我假设您对EXCHANGE分区也有相同的限制。也许你可以暂时禁用它们。对不起。。。我不明白。我必须创建一个没有分区的空表,然后用它做什么?@MarllonNasser-Tom-kyte已经解决了这个问题。看见2006年4月2日的消息我应该先添加此链接。
CREATE TABLE prova_log_old (
       id_dispositive       NUMBER,
       TYPE                 NUMBER,
       date_verification    DATE,
       status               NUMBER
);
 EXECUTE IMMEDIATE    'alter table PROVA_LOG EXCHANGE PARTITION '
                           || item.partition_name
                           || ' with table PROVA_LOG_OLD';