All Products
Search
Document Center

MaxCompute:Insert or overwrite data into dynamic partitions (DYNAMIC PARTITION)

Last Updated:Mar 26, 2026

When writing data to a partitioned table, you normally specify both the partition column name and its value. With dynamic partitions, you specify only the column name — MaxCompute reads the value from each row in your SELECT output and routes data to the matching partition automatically, creating any missing partitions on the fly.

For static partition inserts, see Insert or update data into a table or a static partition (INSERT INTO and INSERT OVERWRITE).

Prerequisites

Before you begin, ensure that you have:

  • Update permission on the destination table

  • Select permission on the metadata of the source table

For permission details, see MaxCompute permissions.

How dynamic partitioning works

Specify partition key column names (not values) in the PARTITION clause. Include the partition values as the trailing columns in your SELECT list — MaxCompute maps them to partition slots in column order, not by column name.

For example, to insert into a table partitioned by region:

INSERT OVERWRITE TABLE total_revenues PARTITION(region)
SELECT total_price AS revenue, region FROM sale_detail;

MaxCompute reads the region value from each source row and routes data to the corresponding partition, creating partitions automatically when they don't exist.

Important

Partition values are assigned by column position, not by name. The last columns in SELECT fill partition slots in the order declared in PARTITION(...). Always verify that the trailing SELECT columns match the partition column declaration order — a name match does not guarantee correct mapping.

Syntax

INSERT {INTO|OVERWRITE} TABLE <table_name> PARTITION (<ptcol_name>[, <ptcol_name> ...])
<select_statement> FROM <from_statement>;
TABLE is required in INSERT OVERWRITE TABLE <table_name> and cannot be omitted. In INSERT INTO TABLE <table_name>, TABLE is optional.

Parameters

ParameterRequiredDescription
table_nameYesName of the destination table.
ptcol_nameYesName of a partition key column in the destination table. List all dynamic partition columns here without values. If you mix static and dynamic partitions, static partitions must be declared at a higher level than dynamic ones — for example, PARTITION (sale_date='2013', region) is valid; PARTITION (sale_date, region='china') is not.
select_statementYesSELECT clause that queries the source data. The trailing columns in the select list map to dynamic partition values by position, not by name.
from_statementYesFROM clause specifying the data source.

Limitations

ConstraintLimit
Max dynamic partitions per INSERT INTO10,000
Max dynamic partitions per INSERT OVERWRITE60,000
Max dynamic partitions per SQL statement in a distributed environment512 (exceeding this causes an exception)
Clustered tablesNot supported

Partition key value rules:

  • Cannot be NULL or contain unsupported special characters (error: FAILED: ODPS-0123031: Partition exception - invalid dynamic partition value: province=xxx)

  • Cannot contain double-byte characters (such as Chinese characters)

  • Must start with a letter

  • Length: 1–255 bytes

  • Supported special characters: spaces, colons (:), underscores (_), dollar signs ($), number signs (#), periods (.), exclamation points (!), at signs (@)

  • Behavior of escape characters \t, \n, and / is undefined

Note

If your data is ordered, inserting it into dynamic partitions scatters the data randomly, reducing the compression ratio. To preserve order and improve compression, use Tunnel commands instead. For an end-to-end example, see Migrate data from ApsaraDB RDS to MaxCompute based on dynamic partitioning.

Partition creation and concurrency

  • If the target partition doesn't exist, MaxCompute creates it automatically.

  • When multiple concurrent jobs write to the same non-existent partition simultaneously, only the first successfully executed job creates the partition — one partition per job.

  • To avoid concurrency conflicts, run ALTER TABLE to create partitions in advance. See Partition operations.

  • If the partition key column type doesn't match the SELECT column type, MaxCompute performs an implicit conversion.

Supported clients

Run dynamic partition insert statements from any of the following clients:

Sample data

The examples below use the following sale_detail table. Run this setup before trying the examples.

-- Create the partitioned table
CREATE TABLE IF NOT EXISTS sale_detail
(
  shop_name     STRING,
  customer_id   STRING,
  total_price   DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);

-- Add a partition (optional — MaxCompute creates partitions automatically on write)
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china');

-- Load sample data
INSERT INTO sale_detail PARTITION (sale_date='2013', region='china')
VALUES ('s1','c1',100.1), ('s2','c2',100.2), ('s3','c3',100.3);

-- Verify
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail;

Expected output:

+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| s1         | c1          | 100.1       | 2013       | china      |
| s2         | c2          | 100.2       | 2013       | china      |
| s3         | c3          | 100.3       | 2013       | china      |
+------------+-------------+-------------+------------+------------+

Examples

Insert into a single-level dynamic partition

Create a destination table with one partition level and let MaxCompute assign partition values from the source data:

-- Create destination table
CREATE TABLE total_revenues (revenue DOUBLE) PARTITIONED BY (region STRING);

-- Insert with dynamic partition
SET odps.sql.allow.fullscan=true;
INSERT OVERWRITE TABLE total_revenues PARTITION(region)
SELECT total_price AS revenue, region FROM sale_detail;

-- Verify partitions created
SHOW PARTITIONS total_revenues;

SHOW PARTITIONS output:

region=china

Data in total_revenues:

SET odps.sql.allow.fullscan=true;
SELECT * FROM total_revenues;
+------------+------------+
| revenue    | region     |
+------------+------------+
| 100.1      | china      |
| 100.2      | china      |
| 100.3      | china      |
+------------+------------+

Mix static and dynamic partitions

When a table has multiple partition levels, fix the high-level partition as static and leave lower levels dynamic:

-- Create destination table with same schema as sale_detail
CREATE TABLE sale_detail_dypart LIKE sale_detail;

-- Fix sale_date as static, leave region dynamic
SET odps.sql.allow.fullscan=true;
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date='2013', region)
SELECT shop_name, customer_id, total_price, region FROM sale_detail;

-- Verify
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail_dypart;
+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| s1         | c1          | 100.1       | 2013       | china      |
| s2         | c2          | 100.2       | 2013       | china      |
| s3         | c3          | 100.3       | 2013       | china      |
+------------+-------------+-------------+------------+------------+

Understand column order in dynamic partition mapping

Dynamic partition values are mapped by column position, not column name. The last columns in SELECT fill partition slots in the order declared in PARTITION(...).

Correct column ordersale_date maps to sale_date, region maps to region:

SET odps.sql.allow.fullscan=true;
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date, region)
SELECT shop_name, customer_id, total_price, sale_date, region FROM sale_detail;

Swapped column orderregion maps to sale_date, sale_date maps to region:

SET odps.sql.allow.fullscan=true;
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date, region)
SELECT shop_name, customer_id, total_price, region, sale_date FROM sale_detail;

With swapped columns, the partition values are reversed. Each source row appears twice — once per original partition — with partition values swapped:

+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| s1         | c1          | 100.1       | china      | 2013       |
| s2         | c2          | 100.2       | china      | 2013       |
| s3         | c3          | 100.3       | china      | 2013       |
| s1         | c1          | 100.1       | 2013       | china      |
| s2         | c2          | 100.2       | 2013       | china      |
| s3         | c3          | 100.3       | 2013       | china      |
+------------+-------------+-------------+------------+------------+

Use implicit type conversion for partition values

If the partition key column type doesn't match the trailing SELECT column type, MaxCompute converts the value automatically. In this example, a TIMESTAMP value from CURRENT_TIMESTAMP() is stored in a STRING partition column:

-- Create source table
CREATE TABLE src (c INT, d STRING) PARTITIONED BY (e INT);
ALTER TABLE src ADD IF NOT EXISTS PARTITION (e=201312);
INSERT INTO src PARTITION (e=201312) VALUES (1,100.1),(2,100.2),(3,100.3);

-- Create destination table with STRING partition
CREATE TABLE parttable(a INT, b DOUBLE) PARTITIONED BY (p STRING);

-- Insert with implicit conversion: TIMESTAMP to STRING
SET odps.sql.allow.fullscan=true;
INSERT INTO parttable PARTITION (p) SELECT c, d, CURRENT_TIMESTAMP() FROM src;

-- Verify
SET odps.sql.allow.fullscan=true;
SELECT * FROM parttable;
+------------+------------+-------------------------+
| a          | b          | p                       |
+------------+------------+-------------------------+
| 1          | 100.1      | 2024-12-10 15:59:34.492 |
| 2          | 100.2      | 2024-12-10 15:59:34.492 |
| 3          | 100.3      | 2024-12-10 15:59:34.492 |
+------------+------------+-------------------------+

Common errors

Missing partition columns in SELECT

Error:

FAILED: ODPS-0130071:[1,24] Semantic analysis exception - wrong columns count 3 in data source, requires 4 columns (includes dynamic partitions if any)

Cause: The SELECT list doesn't include the dynamic partition column. For a table with 3 data columns and 1 dynamic partition, SELECT must return 4 columns total.

Fix: Add the partition key column to SELECT:

-- Incorrect: SELECT returns only 3 columns, but 4 are required
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date='2013', region)
SELECT shop_name, customer_id, total_price FROM sale_detail;

-- Correct: include region as the 4th column
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date='2013', region)
SELECT shop_name, customer_id, total_price, region FROM sale_detail;

Static partition specified at sub-partition level

Error:

FAILED: ODPS-0130071:[1,72] Semantic analysis exception - static partition region must be a high level partition than any dynamic partitions

Cause: A static value was assigned to a lower-level partition while a higher-level partition was left dynamic.

Fix: Declare static partitions at a higher level than dynamic ones:

-- Incorrect: high-level partition (sale_date) is dynamic, low-level (region) is static
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date, region='china')
SELECT shop_name, customer_id, total_price, sale_date FROM sale_detail_dypart;

-- Correct: high-level partition (sale_date) is static, low-level (region) is dynamic
INSERT OVERWRITE TABLE sale_detail_dypart PARTITION (sale_date='2013', region)
SELECT shop_name, customer_id, total_price, region FROM sale_detail;

Related topics