oracle 12c r2起支持多列列表分区,需显式指定括号包裹的列名及元组形式values,不支持automatic、alter table转分区,null需显式匹配,default分区可捕获未定义组合。
oracle 12c r2(12.2+)才支持多列列表分区,低于该版本直接报错;语法上必须显式列出所有列名,不能省略括号或用通配符。
CREATE TABLE 时指定多列列表分区的写法
多列列表分区要求在 PARTITION BY LIST 后跟括号包裹的逗号分隔列名,每个分区的 VALUES 必须是对应列值的元组(括号内嵌套括号),不是单个值拼接。
常见错误现象:
- 写成
PARTITION BY LIST (col1, col2)但VALUES ('A','B')—— 缺少外层括号,报ORA-00920: invalid relational operator - 漏掉任意一个列名,比如只写
PARTITION BY LIST (col1)却想按两列分区 —— 实际仍是单列列表分区,第二列被忽略 - 用空格或竖线分隔值,如
VALUES ('A' 'B')或VALUES ('A'|'B')—— 语法不合法
正确示例:
CREATE TABLE orders_by_region (
order_id NUMBER,
country_code VARCHAR2(3),
region VARCHAR2(10),
amount NUMBER
) PARTITION BY LIST (country_code, region) (
PARTITION p_uk_london VALUES (('GBR', 'LONDON')),
PARTITION p_us_ny VALUES (('USA', 'NEW YORK'), ('USA', 'BUFFALO')),
PARTITION p_jp_tokyo VALUES (('JPN', 'TOKYO')),
PARTITION p_default VALUES (DEFAULT)
);
注意:DEFAULT 分区可选,但一旦使用,它会捕获所有未显式定义的组合(包括 (NULL, 'LONDON') 这类含 NULL 的情况)。
插入数据时值匹配规则与 NULL 处理
Oracle 按顺序严格比对每一列值。如果某列是 NULL,只有当该列在对应分区的 VALUES 元组中也明确为 NULL(即写成 (NULL, 'LONDON')),才能命中;否则落入 DEFAULT 分区(若存在)或报 ORA-14400。
关键点:
-
INSERT INTO orders_by_region VALUES (1, 'USA', NULL, 100)不会进p_us_ny,因为p_us_ny定义的是('USA', 'NEW YORK')和('USA', 'BUFFALO'),不含NULL第二列 - 若没建
DEFAULT分区,这条语句直接报ORA-14400 - 想让
NULL落入特定分区,必须显式写VALUES ((NULL, 'LONDON'))—— 注意双括号:外层表示元组,内层表示值
ALTER TABLE 无法添加多列列表分区
已有表不能通过 ALTER TABLE ... PARTITION BY LIST 改成分区表,更不能改成多列列表分区。Oracle 不支持对非分区表在线转为多列列表分区表。
可行路径只有两条:
- 导出数据 → 用新 DDL 创建多列列表分区表 → 导入数据(推荐用于生产环境,可控性强)
- 用
DBMS_REDEFINITION在线重定义(要求源表有主键或唯一约束,且需额外空间和权限)
别试 ALTER TABLE t ADD PARTITION ... —— 它只适用于已分区表新增分区,不适用于从无分区到有分区的结构变更。
多列列表分区 + AUTOMATIC 的兼容性陷阱
AUTOMATIC 关键字**不支持多列列表分区**。官方文档和实测均确认:只要 PARTITION BY LIST 后是多列,就不能加 AUTOMATIC,否则报 ORA-02158: invalid CREATE TABLE option。
这意味着:
- 你必须预先枚举所有业务上可能出现的(country_code, region)组合,或依赖
DEFAULT分区兜底 - 不能指望 Oracle 自动为新出现的
('FRA', 'PARIS')创建分区 —— 它不会发生 - 如果组合太多、变化频繁,多列列表分区反而增加维护负担,此时应考虑降维:比如把
(country_code, region)预计算为一个业务码字段(如loc_code),再对单列做AUTOMATIC LIST
最后提醒一句:系统生成的分区名(如 SYS_P12345)只出现在单列 AUTOMATIC 场景下;多列列表分区的所有分区名都由你显式定义,所以命名要清晰,别用 p1、p2 这种无法追溯业务含义的名字。











