By Mouhamadou Diaw

When creating a database in a multitenant environment we must understand how character set works for CDB and PDBS.

In Oracle documentation we can find following lines

-When the character set of the CDB root is AL32UTF8, PDBs that are plugged into the CDB can have a different character set from the CDB root.
PDBs that you create from PDB$SEED inherit the AL32UTF8 character set from it, but you can migrate the PDB to a different character set.

-When the character set of the root is not AL32UTF8, all PDBs in the CDB use the character set of the CDB root.

Let’s see how it works. Suppose I have 2 non-CDB databases DB11G and DB12C and I want to migrate them in an Oracle 21c container.

As specified in the documentation we have to create a container with AL32UTF8 as character set. If not, we will not be able to create a PDB with AL32UTF8 as character set.

Ok so the first step is to create the CDB CDBPROD.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
SQL> select name from v$database;
NAME
---------
CDBPROD
SQL> select value,parameter from NLS_DATABASE_PARAMETERS where PARAMETER like '%CHARACTERSET';
VALUE                               PARAMETER
----------------------------------- -----------------------------------
AL16UTF16                           NLS_NCHAR_CHARACTERSET
AL32UTF8                            NLS_CHARACTERSET
SQL>

And in this container CDBPROD let’s create the DB21UTF from seed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SQL> CREATE PLUGGABLE DATABASE DB21UTF ADMIN USER db21admin identified by root;
Pluggable database created.
SQL> alter pluggable database DB21UTF open;
Pluggable database altered.
SQL> show pdbs
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         4 DB21UTF                        READ WRITE NO
SQL>

And in DB21UTF the character set will be same as CDB$ROOT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SQL> alter session set container=DB21UTF;
Session altered.
SQL> show con_name;
CON_NAME
------------------------------
DB21UTF
SQL> select value,parameter from NLS_DATABASE_PARAMETERS where PARAMETER like '%CHARACTERSET';
VALUE                          PARAMETER
------------------------------ ------------------------------
AL16UTF16                      NLS_NCHAR_CHARACTERSET
AL32UTF8                       NLS_CHARACTERSET
SQL>

And then in DB21UTF, I can import data of DB11G.

But how can I create the PDB DB21ISO in CDBPROD with WE8ISO8859P15 as character set. One way is to
-create another CDB CDBISO with the character set WE8ISO8859P15
-create the PDB DBISO in this new CDB CDBISO
-Clone this DBISO in the CDBPROD

Ok let’s do that, below information of the new ISO CDB with the PDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SQL> select name from v$database;
NAME
---------
CDBISO
SQL> show pdbs
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 DB21ISO                        READ WRITE NO
SQL> select value,parameter from NLS_DATABASE_PARAMETERS where PARAMETER like '%CHARACTERSET';
VALUE                          PARAMETER
------------------------------ ------------------------------
AL16UTF16                      NLS_NCHAR_CHARACTERSET
WE8ISO8859P15                  NLS_CHARACTERSET
SQL>

Now let’s clone DBISO in CDBPROD

On CDBISO let’s create a user we will use for a database link

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
SQL> create user c##clone_user identified by root default tablespace users temporary tablespace temp container=ALL;
User created.
SQL> grant create session, create pluggable database, sysoper to c##clone_user container=ALL;
Grant succeeded.
SQL>

On CDBPROD let’s create a database link

Verify your TNS alias

1
2
3
4
5
6
7
8
9
10
11
12
13
14
oracle@oraadserver:/home/oracle/ [CDBPROD (CDB$ROOT)] tnsping cdbiso
TNS Ping Utility for Linux: Version 21.0.0.0.0 - Production on 10-FEB-2022 15:44:03
Copyright (c) 1997, 2021, Oracle.  All rights reserved.
Used parameter files:
/u01/app/oracle/network/admin/sqlnet.ora
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = oraadserver)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = CDBISO)))
OK (0 msec)
oracle@oraadserver:/home/oracle/ [CDBPROD (CDB$ROOT)]

Create the dblink

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SQL> select name from v$database;
NAME
---------
CDBPROD
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
SQL> create database link cloneiso connect to c##clone_user identified by root using 'CDBISO';
Database link created.
SQL> select * from dual@cloneiso;
D
-
X
SQL>

And then clone the DBISO PDB in CDBPROD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SQL> select name from v$database;
NAME
---------
CDBPROD
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
SQL> create pluggable database DB21ISO from DB21ISO@cloneiso;
Pluggable database created.
SQL> alter pluggable database DB21ISO open;
Pluggable database altered.

Now let’s verify the state of my PDBs in CDBPROD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SQL> select name from v$database;
NAME
---------
CDBPROD
SQL>
SQL> show pdbs
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         4 DB21UTF                        READ WRITE NO
         7 DB21ISO                        READ WRITE NO
SQL>

Let’s verify the DB21ISO character set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SQL> select name from v$database;
NAME
---------
CDBPROD
SQL> alter session set container=DB21ISO;
Session altered.
SQL> select value,parameter from NLS_DATABASE_PARAMETERS where PARAMETER like '%CHARACTERSET';
SQL> col value for a35
SQL> col parameter for a35
SQL> select value,parameter from NLS_DATABASE_PARAMETERS where PARAMETER like '%CHARACTERSET';
VALUE                               PARAMETER
----------------------------------- -----------------------------------
AL16UTF16                           NLS_NCHAR_CHARACTERSET
WE8ISO8859P15                       NLS_CHARACTERSET
SQL>

And the CDBPROD as seen before has AL32UTF8 as character set

1
2
3
4
5
6
7
8
9
10
SQL> conn / as sysdba
Connected.
SQL> select value,parameter from NLS_DATABASE_PARAMETERS where PARAMETER like '%CHARACTERSET';
VALUE                               PARAMETER
----------------------------------- -----------------------------------
AL16UTF16                           NLS_NCHAR_CHARACTERSET
AL32UTF8                            NLS_CHARACTERSET
SQL>

Conclusion

Always use AL32UTF8 for your CDB if possible, in this way you will be able to have PDBs with different character set