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.
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>;TABLEis required inINSERT OVERWRITE TABLE <table_name>and cannot be omitted. InINSERT INTO TABLE <table_name>,TABLEis optional.
Parameters
| Parameter | Required | Description |
|---|---|---|
table_name | Yes | Name of the destination table. |
ptcol_name | Yes | Name 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_statement | Yes | SELECT clause that queries the source data. The trailing columns in the select list map to dynamic partition values by position, not by name. |
from_statement | Yes | FROM clause specifying the data source. |
Limitations
| Constraint | Limit |
|---|---|
Max dynamic partitions per INSERT INTO | 10,000 |
Max dynamic partitions per INSERT OVERWRITE | 60,000 |
| Max dynamic partitions per SQL statement in a distributed environment | 512 (exceeding this causes an exception) |
| Clustered tables | Not 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
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 TABLEto create partitions in advance. See Partition operations.If the partition key column type doesn't match the
SELECTcolumn 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=chinaData 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 order — sale_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 order — region 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 partitionsCause: 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;