Search code examples
oracle10gdatabase-partitioning

how to drop oracle partition with partition name as generated parameter


i have to drop partitions which are older than 364 days. Partitions are named as "log_20110101", so partitions which are older than today will have to be

CONCAT('log_',TO_CHAR(SYSDATE -364,'YYYYMMDD'))

now if i try such a statement i get error

ALTER TABLE LOG
DROP PARTITION CONCAT('log_',TO_CHAR(SYSDATE -364,'YYYYMMDD'));

-

Error report:
SQL Error: ORA-14048: a partition maintenance operation may not be combined with other operations
14048. 00000 -  "a partition maintenance operation may not be combined with other operations"
*Cause:    ALTER TABLE or ALTER INDEX statement attempted to combine
           a partition maintenance operation (e.g. MOVE PARTITION) with some
           other operation (e.g. ADD PARTITION or PCTFREE which is illegal
*Action:   Ensure that a partition maintenance operation is the sole
           operation specified in ALTER TABLE or ALTER INDEX statement;
           operations other than those dealing with partitions,
           default attributes of partitioned tables/indices or
           specifying that a table be renamed (ALTER TABLE RENAME) may be
           combined at will

Solution

  • The partition name needs to be fixed at the time you issue the SQL statement, it cannot be an expression. You should be able to do something like this where you iterate over the USER_TAB_PARTITIONS table, figure out which partitions to drop, and construct the dynamic SQL to actually drop them.

    DECLARE
      l_sql_stmt VARCHAR2(1000);
      l_date     DATE;
    BEGIN
      FOR x IN (SELECT * 
                  FROM user_tab_partitions
                 WHERE table_name = 'LOG')
      LOOP
        l_date := to_date( substr( x.partition_name, 5 ), 'YYYYMMDD' );
        IF( l_date < add_months( trunc(sysdate), -12 ) )
        THEN
          l_sql_stmt := 'ALTER TABLE log ' ||
                        ' DROP PARTITION ' || x.partition_name;
          dbms_output.put_line( l_sql_stmt );
          EXECUTE IMMEDIATE l_sql_stmt;
        END IF;
      END LOOP;
    END;