Problém je v ; znak v 'SELECT * FROM DUAL;' .
Z dokumentace :
execute_immediate_statement ::=
EXECUTE_IMMEDIATE dynamic_string
{
INTO { define_variable [, define_variable ...] | record_name }
| BULK COLLECT INTO { collection_name [, collection_name ...] | :host_array_name }
}
[ USING [ IN | OUT | IN OUT ] bind_argument
[, [ IN | OUT | IN OUT ] bind_argument] ... ] [ returning_clause ] ;
... kde dynamic_string je (zdůrazňuji můj):
Protože nebude přijímat více příkazů, pokud je neuzavřete do jednoho bloku PL/SQL, ; oddělovač se neočekává.
Lepší vysvětlení najdete na stránce Použití příkazu EXECUTE IMMEDIATE v PL/SQL :