Хорошая попытка, но согласно документации Oracle 10g, синтаксис CREATE INDEX и ALTER TABLE ADD CONSTRAINT в этом отношении не взаимозаменяемы, поэтому вы получили эту синтаксическую ошибку:
CREATE INDEX ::=
CREATE [ UNIQUE | BITMAP ] INDEX [ schema. ]index
ON { cluster_index_clause
| table_index_clause
| bitmap_join_index_clause
} ;
table_index_clause ::=
[ schema. ]table [ t_alias ]
(index_expr [ ASC | DESC ]
[, index_expr [ ASC | DESC ] ]...)
[ index_properties ]
index_expr ::= { column | column_expression }
Следовательно, CREATE INDEX допускает выражение column_expression, которое по сути является «индексом на основе функций».
С другой стороны:
ALTER TABLE ::=
ALTER TABLE [ schema. ]table
[ alter_table_properties
| column_clauses
| constraint_clauses
| alter_table_partitioning
| alter_external_table_clauses
| move_table_clause
]
[ enable_disable_clause
| { ENABLE | DISABLE }
{ TABLE LOCK | ALL TRIGGERS }
[ enable_disable_clause
| { ENABLE | DISABLE }
{ TABLE LOCK | ALL TRIGGERS }
]...
] ;
constraint_clauses ::=
{ ADD { out_of_line_constraint
[ out_of_line_constraint ]...
| out_of_line_REF_constraint
}
| MODIFY { CONSTRAINT constraint
| PRIMARY KEY
| UNIQUE (column [, column ]...)
}
constraint_state
| RENAME CONSTRAINT old_name TO new_name
| drop_constraint_clause
}
out_of_line_constraint ::=
[ CONSTRAINT constraint_name ]
{ UNIQUE (column [, column ]...)
| PRIMARY KEY (column [, column ]...)
| FOREIGN KEY (column [, column ]...)
references_clause
| CHECK (condition)
}
[ constraint_state ]
Следовательно, определение УНИКАЛЬНОГО ограничения может быть только именами столбцов и не может быть выражениями столбцов.
Вы можете сделать это в 11g, используя виртуальные столбцы, в 10g и более ранних версиях большинство людей, как правило, создают производные столбцы (наряду с бременем их обновления программно).