SQL Error: ORA-14006: invalid partition name
SQL Error: ORA-14006: invalid partition name
我正在尝试使用以下 SQL 语句对 Oracle 12C R1 中现有的 table 进行分区。
ALTER TABLE TABLE_NAME MODIFY
PARTITION BY RANGE (DATE_COLUMN_NAME)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION part_01 VALUES LESS THAN (TO_DATE('01-SEP-2017', 'DD-MON-RRRR'))
) ONLINE;
获取错误:
Error report -
SQL Error: ORA-14006: invalid partition name
14006. 00000 - "invalid partition name"
*Cause: a partition name of the form <identifier> is
expected but not present.
*Action: enter an appropriate partition name.
需要按照data数据类型列进行分区,间隔为1个月
Table 中日期时间列的最小值为 01-SEP-2017。
您不能像那样对现有 table 进行分区。该语句正在修改尚未创建的分区。我不知道执行此操作的自动方式,我不确定您是否可以执行此操作。
虽然这件事我已经做过很多次了,但是都是手动操作的。如果找不到自动化解决方案,请执行以下操作:
- 创建一个分区 table,命名为 table_name_part,包含您的子句和所有偏好。
- 将原始 table 中的所有行插入此分区 table。注意压缩。如果您对 table(基本或 HCC)进行了一些压缩,则必须使用 + APPEND 提示。
- 在分区 table 上创建原始 table 的约束和索引。
- 重命名 table 并删除原来的 table。在对它们进行一些计数之前不要放弃它。
我看到您的 table 可以选择自动创建不存在的分区。 (NUMTOYMINTERVAL(1,'MONTH')) 因此您必须仅使用第一个分区创建 table。我假设你这里有很多只读数据,所以你不会有任何一致性问题而不是上个月。可能有一些读写数据,所以当你想在新 table 中插入数据并切换 tables.
时,你必须更加小心
希望能帮到你。据我所知,可能有一个名为 DBMS_REDEFINITION 的包可以帮助您完成我的步骤的自动化版本。如果您需要更多详细信息或需要有关我的方法的帮助,请不要犹豫。
更新:
从 Oracle 12c R2 开始,您可以使用您的方法将 table 从未分区转换为分区。在下面找到一个link。现在这对我来说是一个挑战,我正在尝试转换,但我认为在 12c R1 中无法在线进行此转换。
In previous releases you could partition a non-partitioned table using
EXCHANGE PARTITION or DBMS_REDEFINITION in an "almost online" manner,
but both methods require multiple steps. Oracle Database 12c Release 2
makes it easier than ever to convert a non-partitioned table to a
partitioned table, requiring only a single command and no downtime.
解决方案
我为您找到了解决方案。在这里,您将看到我 运行 在线转换 table 的所有步骤。 :)
1. Create regular table and populate it.
CREATE TABLE SCOTT.tab_unpartitioned
(
id NUMBER,
description VARCHAR2 ( 50 ),
created_date DATE
);
INSERT INTO tab_unpartitioned
SELECT LEVEL,
'Description for ' || LEVEL,
ADD_MONTHS ( TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' ),
-TRUNC ( DBMS_RANDOM.VALUE ( 1, 4 ) - 1 ) * 12 )
FROM DUAL
CONNECT BY LEVEL <= 10000;
COMMIT;
2. Create partitioned table with same structure.
--If you are on 11g create table with CREATE TABLE command but with different name. ex: tab_partitioned
CREATE TABLE SCOTT.tab_partitioned
(
id NUMBER,
description VARCHAR2 ( 50 ),
created_date DATE
)
PARTITION BY RANGE (created_date)
INTERVAL( NUMTOYMINTERVAL(1,'YEAR'))
(PARTITION part_2015 VALUES LESS THAN (TO_DATE ( '01-JAN-2016', 'DD-MON-YYYY' )),
PARTITION part_2016 VALUES LESS THAN (TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' )),
PARTITION part_2017 VALUES LESS THAN (TO_DATE ( '01-JAN-2018', 'DD-MON-YYYY' )));
--this is an alter command that works only in 12c.
ALTER TABLE tab_partitioned
MODIFY
PARTITION BY RANGE (created_date)
(PARTITION part_2015 VALUES LESS THAN (TO_DATE ( '01-JAN-2016', 'DD-MON-YYYY' )),
PARTITION part_2016 VALUES LESS THAN (TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' )),
PARTITION part_2017 VALUES LESS THAN (TO_DATE ( '01-JAN-2018', 'DD-MON-YYYY' )));
3. Check if the table can be converted. This procedure should run without any error.
Prerequisites: table should have an UNIQUE INDEX and a Primary Key constraint.
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED');
4. Run the following steps like I have done.
EXEC DBMS_REDEFINITION.START_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
var num_errors varchar2(2000);
EXEC DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED', 1,TRUE,TRUE,TRUE,FALSE,:NUM_ERRORS,FALSE);
SQL> PRINT NUM_ERRORS -- Should return 0
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
在脚本的最后你会看到原来的table被分区了。
试试Oracle Live SQL我以前用的是Oracle 11g EE,也有同样的错误信息。所以我尝试了 Oracle live SQL,它运行良好。它有非常简单易懂的界面,
例如,我正在创建销售 table 并插入一些虚拟数据并使用范围分区方法对其进行分区,
CREATE TABLE sales
(product VARCHAR(300),
country VARCHAR(100),
sales_year DATE);
INSERT INTO sales (product, country, sales_year )
VALUES ('Computer','Kazakhstan',TO_DATE('01/02/2018','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Mobile Phone','China',TO_DATE('23/12/2019','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Camara','USA',TO_DATE('20/11/2020','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Watch','Bangladesh',TO_DATE('19/03/2020','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Cake','Sri Lanka',TO_DATE('13/04/2021','DD/MM/YYYY'));
ALTER TABLE sales MODIFY
PARTITION BY RANGE(sales_year)
INTERVAL(INTERVAL '1' YEAR)
(
PARTITION sales_2018 VALUES LESS THAN(TO_DATE('01/01/2019','DD/MM/YYYY')),
PARTITION sales_2019 VALUES LESS THAN(TO_DATE('01/01/2020','DD/MM/YYYY')),
PARTITION sales_2020 VALUES LESS THAN(TO_DATE('01/01/2021','DD/MM/YYYY')),
PARTITION sales_2021 VALUES LESS THAN(TO_DATE('01/01/2022','DD/MM/YYYY'))
)ONLINE;
最后,我可以编写 SELECT
查询分区以确认分区创建成功。
SELECT *
FROM sales PARTITION (sales_2020);
它给出了预期的输出,
我正在尝试使用以下 SQL 语句对 Oracle 12C R1 中现有的 table 进行分区。
ALTER TABLE TABLE_NAME MODIFY
PARTITION BY RANGE (DATE_COLUMN_NAME)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION part_01 VALUES LESS THAN (TO_DATE('01-SEP-2017', 'DD-MON-RRRR'))
) ONLINE;
获取错误:
Error report -
SQL Error: ORA-14006: invalid partition name
14006. 00000 - "invalid partition name"
*Cause: a partition name of the form <identifier> is
expected but not present.
*Action: enter an appropriate partition name.
需要按照data数据类型列进行分区,间隔为1个月
Table 中日期时间列的最小值为 01-SEP-2017。
您不能像那样对现有 table 进行分区。该语句正在修改尚未创建的分区。我不知道执行此操作的自动方式,我不确定您是否可以执行此操作。
虽然这件事我已经做过很多次了,但是都是手动操作的。如果找不到自动化解决方案,请执行以下操作:
- 创建一个分区 table,命名为 table_name_part,包含您的子句和所有偏好。
- 将原始 table 中的所有行插入此分区 table。注意压缩。如果您对 table(基本或 HCC)进行了一些压缩,则必须使用 + APPEND 提示。
- 在分区 table 上创建原始 table 的约束和索引。
- 重命名 table 并删除原来的 table。在对它们进行一些计数之前不要放弃它。
我看到您的 table 可以选择自动创建不存在的分区。 (NUMTOYMINTERVAL(1,'MONTH')) 因此您必须仅使用第一个分区创建 table。我假设你这里有很多只读数据,所以你不会有任何一致性问题而不是上个月。可能有一些读写数据,所以当你想在新 table 中插入数据并切换 tables.
时,你必须更加小心希望能帮到你。据我所知,可能有一个名为 DBMS_REDEFINITION 的包可以帮助您完成我的步骤的自动化版本。如果您需要更多详细信息或需要有关我的方法的帮助,请不要犹豫。
更新: 从 Oracle 12c R2 开始,您可以使用您的方法将 table 从未分区转换为分区。在下面找到一个link。现在这对我来说是一个挑战,我正在尝试转换,但我认为在 12c R1 中无法在线进行此转换。
In previous releases you could partition a non-partitioned table using EXCHANGE PARTITION or DBMS_REDEFINITION in an "almost online" manner, but both methods require multiple steps. Oracle Database 12c Release 2 makes it easier than ever to convert a non-partitioned table to a partitioned table, requiring only a single command and no downtime.
解决方案
我为您找到了解决方案。在这里,您将看到我 运行 在线转换 table 的所有步骤。 :)
1. Create regular table and populate it.
CREATE TABLE SCOTT.tab_unpartitioned
(
id NUMBER,
description VARCHAR2 ( 50 ),
created_date DATE
);
INSERT INTO tab_unpartitioned
SELECT LEVEL,
'Description for ' || LEVEL,
ADD_MONTHS ( TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' ),
-TRUNC ( DBMS_RANDOM.VALUE ( 1, 4 ) - 1 ) * 12 )
FROM DUAL
CONNECT BY LEVEL <= 10000;
COMMIT;
2. Create partitioned table with same structure.
--If you are on 11g create table with CREATE TABLE command but with different name. ex: tab_partitioned
CREATE TABLE SCOTT.tab_partitioned
(
id NUMBER,
description VARCHAR2 ( 50 ),
created_date DATE
)
PARTITION BY RANGE (created_date)
INTERVAL( NUMTOYMINTERVAL(1,'YEAR'))
(PARTITION part_2015 VALUES LESS THAN (TO_DATE ( '01-JAN-2016', 'DD-MON-YYYY' )),
PARTITION part_2016 VALUES LESS THAN (TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' )),
PARTITION part_2017 VALUES LESS THAN (TO_DATE ( '01-JAN-2018', 'DD-MON-YYYY' )));
--this is an alter command that works only in 12c.
ALTER TABLE tab_partitioned
MODIFY
PARTITION BY RANGE (created_date)
(PARTITION part_2015 VALUES LESS THAN (TO_DATE ( '01-JAN-2016', 'DD-MON-YYYY' )),
PARTITION part_2016 VALUES LESS THAN (TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' )),
PARTITION part_2017 VALUES LESS THAN (TO_DATE ( '01-JAN-2018', 'DD-MON-YYYY' )));
3. Check if the table can be converted. This procedure should run without any error.
Prerequisites: table should have an UNIQUE INDEX and a Primary Key constraint.
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED');
4. Run the following steps like I have done.
EXEC DBMS_REDEFINITION.START_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
var num_errors varchar2(2000);
EXEC DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED', 1,TRUE,TRUE,TRUE,FALSE,:NUM_ERRORS,FALSE);
SQL> PRINT NUM_ERRORS -- Should return 0
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
在脚本的最后你会看到原来的table被分区了。
试试Oracle Live SQL我以前用的是Oracle 11g EE,也有同样的错误信息。所以我尝试了 Oracle live SQL,它运行良好。它有非常简单易懂的界面,
例如,我正在创建销售 table 并插入一些虚拟数据并使用范围分区方法对其进行分区,
CREATE TABLE sales
(product VARCHAR(300),
country VARCHAR(100),
sales_year DATE);
INSERT INTO sales (product, country, sales_year )
VALUES ('Computer','Kazakhstan',TO_DATE('01/02/2018','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Mobile Phone','China',TO_DATE('23/12/2019','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Camara','USA',TO_DATE('20/11/2020','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Watch','Bangladesh',TO_DATE('19/03/2020','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Cake','Sri Lanka',TO_DATE('13/04/2021','DD/MM/YYYY'));
ALTER TABLE sales MODIFY
PARTITION BY RANGE(sales_year)
INTERVAL(INTERVAL '1' YEAR)
(
PARTITION sales_2018 VALUES LESS THAN(TO_DATE('01/01/2019','DD/MM/YYYY')),
PARTITION sales_2019 VALUES LESS THAN(TO_DATE('01/01/2020','DD/MM/YYYY')),
PARTITION sales_2020 VALUES LESS THAN(TO_DATE('01/01/2021','DD/MM/YYYY')),
PARTITION sales_2021 VALUES LESS THAN(TO_DATE('01/01/2022','DD/MM/YYYY'))
)ONLINE;
最后,我可以编写 SELECT
查询分区以确认分区创建成功。
SELECT *
FROM sales PARTITION (sales_2020);
它给出了预期的输出,