背景
以前、Aurora PostgreSQLからFDWでOracle on EC2に接続してMviewの動作を確認をしました。
今回は、FDWの外部テーブルの動作をさらに深掘りし、以下を検証します。
- Oracle(JA16SJIS)の日本語カラム名テーブルを、Aurora PostgreSQL(UTF-8)の外部テーブルで英語カラム名にマッピングできるか
- Mviewリフレッシュが問題なく動作するか
まとめ
- oracle_fdwの
tableオプションにサブクエリを指定することで、Oracleの日本語カラム名をAurora PostgreSQLの外部テーブルで英語カラム名にマッピングできた - サブクエリ方式では
schemaオプションとの併用ができないため、サブクエリ内でスキーマを指定する必要がある - Mviewリフレッシュ(CONCURRENTLY含む)も問題なく動作した
実装
今回、下記の環境でテストします
Sqlplusをインストール
1.こちらにアクセスして下記をダウンロードします
- instantclient-basic-macos.x64-19.16.0.0.0dbru.dmg
- instantclient-sqlplus-macos.x64-19.16.0.0.0dbru.dmg
2.basicをインストールします
/Volumes/instantclient-basic-macos.x64-19.16.0.0.0dbru/install_ic.sh
3.sqlplusをインストールします
/Volumes/instantclient-sqlplus-macos.x64-19.16.0.0.0dbru/install_ic.sh
4.フォルダを移動します
sudo mv /Users/XXXX/Downloads/instantclient_19_16 /usr/local/oracle/
Oracleのセットアップ
インフラ
以前、構築したEC2を使用します。
ユーザ(スキーマ)の作成
- testユーザとfdwuserを作成します
SQL> CREATE USER test IDENTIFIED BY XXXX DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS;
CREATE USER fdwuser IDENTIFIED BY XXXX DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS;
GRANT CONNECT TO test;
GRANT RESOURCE TO test;
GRANT CONNECT TO fdwuser;
User created.
SQL>
User created.
SQL>
Grant succeeded.
SQL>
Grant succeeded.
SQL>
Grant succeeded.
SQL>
テーブルの作成(testスキーマ)
2種類のテーブルを作成します。
- testユーザでOracleに接続します
英字カラムのテーブルを作成
1.employeeテーブルを作成します。
SQL> CREATE TABLE employees (
id NUMBER PRIMARY KEY,
name VARCHAR2(100),
department VARCHAR2(50),
created_date DATE DEFAULT SYSDATE
); 2 3 4 5 6
Table created.
SQL>
SQL> desc employees
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
NAME VARCHAR2(100)
DEPARTMENT VARCHAR2(50)
CREATED_DATE DATE
SQL>
2.データを登録します
SQL> INSERT INTO employees VALUES (1, 'Tanaka Taro', 'Sales', SYSDATE);
INSERT INTO employees VALUES (2, 'Suzuki Hanako', 'Engineering', SYSDATE);
INSERT INTO employees VALUES (3, 'Sato Jiro', 'Marketing', SYSDATE);
COMMIT;
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
Commit complete.
SQL>
3.データが登録されました
SQL> SELECT * FROM employees;
ID NAME DEPARTMENT CREATED_DATE
---------- ---------------------------------------------------------------------------------------------------- -------------------------------------------------- -------------------
1 Tanaka Taro Sales 2026/03/20 03:42:07
2 Suzuki Hanako Engineering 2026/03/20 03:42:07
3 Sato Jiro Marketing 2026/03/20 03:42:07
SQL>
日本語カラムテーブルの作成(testスキーマ)
1.PCでターミナルを開きます
2.ポートフォワードします
% aws ssm start-session \
--target i-XXXXXX \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["1521"],"localPortNumber":["1521"]}' \
--region ap-northeast-1
Starting session with SessionId: XXXXXX
Port 1521 opened for sessionId XXXXXX.
Waiting for connections...
3.ターミナルの文字コードを日本語(Shift JIS)に変更します

4.もう一枚ターミナルを開きます
5.環境変数を設定します
export PATH=/usr/local/oracle:$PATH
export DYLD_LIBRARY_PATH=/usr/local/oracle
export NLS_LANG=JAPANESE_JAPAN.JA16SJIS
6.sqlplusで接続します
% sqlplus test/XXXXXX@//localhost:1521/ORCL
SQL*Plus: Release 19.0.0.0.0 - Production on 金 3月 20 12:25:16 2026
Version 19.16.0.0.0
Copyright (c) 1982, 2020, Oracle. All rights reserved.
Oracle Database 11g Release 11.2.0.1.0 - 64bit Production
に接続されました。
SQL>
7.テーブルを作成します
CREATE TABLE employees_jp (
"社員ID" NUMBER PRIMARY KEY,
"氏名" VARCHAR2(100),
"部署" VARCHAR2(50),
"作成日" DATE DEFAULT SYSDATE
);
8.できました
SQL> DESC employees_jp;
名前 NULL? 型
----------------------------------------- -------- ----------------------------
社員ID NOT NULL NUMBER
氏名 VARCHAR2(100)
部署 VARCHAR2(50)
作成日 DATE
SQL>
9.データを登録します
INSERT INTO employees_jp VALUES (101, '山田一郎', '総務部', SYSDATE);
INSERT INTO employees_jp VALUES (102, '高橋美月', '人事部', SYSDATE);
INSERT INTO employees_jp VALUES (103, '渡辺健太', '経理部', SYSDATE);
COMMIT;
10.登録されました
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY/MM/DD HH24:MI:SS';
セッションが変更されました。
SQL> SELECT * FROM employees_jp;
社員ID 氏名 部署 作成日
---------- ---------------------------------------------------------------------------------------------------- -------------------------------------------------- -------------------
101 山田一郎 総務部 2026/03/20 03:34:17
102 高橋美月 人事部 2026/03/20 03:34:17
103 渡辺健太 経理部 2026/03/20 03:34:17
SQL>
fdwuserへの権限付与
1.作成したテーブルに権限を付与します
SQL> GRANT SELECT ON test.employees TO fdwuser;
GRANT SELECT ON test.employees_jp TO fdwuser;
Grant succeeded.
SQL>
Grant succeeded.
SQL>
2.付与されました
SQL> SELECT grantor, table_name, privilege FROM all_tab_privs WHERE grantee = 'FDWUSER';
GRANTOR TABLE_NAME PRIVILEGE
------------------------------ ------------------------------ ----------------------------------------
TEST EMPLOYEES SELECT
TEST EMPLOYEES_JP SELECT
SQL>
Auroraのセットアップ
- psqlでAuroraに接続します
oracle_fdw拡張を有効化
1.oracle_fdw拡張を有効化します
postgres=> CREATE EXTENSION oracle_fdw;
CREATE EXTENSION
postgres=>
2.外部サーバー作成(Oracle EC2に接続) をします
postgres=> CREATE SERVER oracle_ec2
postgres-> FOREIGN DATA WRAPPER oracle_fdw
postgres-> OPTIONS (dbserver '//EC2のIPアドレス:1521/ORCL');
CREATE SERVER
postgres=>
3.ユーザーマッピング(fdwuserで接続)を作成します
postgres=> CREATE USER MAPPING FOR postgres
postgres-> SERVER oracle_ec2
postgres-> OPTIONS (user 'fdwuser', password 'XXXXX');
CREATE USER MAPPING
postgres=>
外部テーブルの作成
英語カラムテーブル
1.外部テーブルを作成します
postgres=> CREATE FOREIGN TABLE fdw_employees (
postgres(> id INTEGER,
postgres(> name VARCHAR(100),
postgres(> department VARCHAR(50),
postgres(> created_date TIMESTAMP
postgres(> ) SERVER oracle_ec2
postgres-> OPTIONS (schema 'TEST', table 'EMPLOYEES');
CREATE FOREIGN TABLE
postgres=>
2.定義を確認します
postgres=> \d fdw_employees
Foreign table "public.fdw_employees"
Column | Type | Collation | Nullable | Default | FDW options
--------------+-----------------------------+-----------+----------+---------+-------------
id | integer | | | |
name | character varying(100) | | | |
department | character varying(50) | | | |
created_date | timestamp without time zone | | | |
Server: oracle_ec2
FDW options: (schema 'TEST', "table" 'EMPLOYEES')
postgres=>
3.見えました
postgres=> select * from fdw_employees;
id | name | department | created_date
----+---------------+-------------+---------------------
1 | Tanaka Taro | Sales | 2026-03-20 03:42:07
2 | Suzuki Hanako | Engineering | 2026-03-20 03:42:07
3 | Sato Jiro | Marketing | 2026-03-20 03:42:07
(3 rows)
postgres=>
日本語カラム→英語カラム名にマッピング
日本語カラムを英語カラムにマッピングするには、tableオプション句でサブクエリのASを使ってカラムを定義します
1.外部テーブルを作成します
postgres=> CREATE FOREIGN TABLE fdw_employees_jp (
postgres(> employee_id INTEGER,
postgres(> name VARCHAR(100),
postgres(> department VARCHAR(50),
postgres(> created_date TIMESTAMP
postgres(> ) SERVER oracle_ec2
postgres-> OPTIONS (table '(SELECT "社員ID" AS employee_id, "氏名" AS name, "部署" AS department, "作成日" AS created_date FROM TEST.employees_jp)');
CREATE FOREIGN TABLE
postgres=>
2.定義を確認します
postgres=> \d fdw_employees_jp
Foreign table "public.fdw_employees_jp"
Column | Type | Collation | Nullable | Default | FDW options
--------------+-----------------------------+-----------+----------+---------+-------------
employee_id | integer | | | |
name | character varying(100) | | | |
department | character varying(50) | | | |
created_date | timestamp without time zone | | | |
Server: oracle_ec2
FDW options: ("table" '(SELECT "社員ID" AS employee_id, "氏名" AS name, "部署" AS department, "作成日" AS created_date FROM TEST.employees_jp)')
postgres=>
3.データも見えました
postgres=> select * from fdw_employees_jp;
employee_id | name | department | created_date
-------------+----------+------------+---------------------
101 | 山田一郎 | 総務部 | 2026-03-20 03:34:17
102 | 高橋美月 | 人事部 | 2026-03-20 03:34:17
103 | 渡辺健太 | 経理部 | 2026-03-20 03:34:17
(3 rows)
postgres=>
postgres=> select employee_id,name from fdw_employees_jp;
employee_id | name
-------------+----------
101 | 山田一郎
102 | 高橋美月
103 | 渡辺健太
(3 rows)
postgres=>
Mviewの作成
英語テーブルのMview
1.Mviewを作成します
postgres=> CREATE MATERIALIZED VIEW mv_employees AS
postgres-> SELECT id, name, department, created_date FROM fdw_employees;
SELECT 3
postgres=>
postgres=> CREATE UNIQUE INDEX idx_mv_employees_id ON mv_employees(id);
CREATE INDEX
postgres=>
2.定義を確認します
postgres=> \d mv_employees
Materialized view "public.mv_employees"
Column | Type | Collation | Nullable | Default
--------------+-----------------------------+-----------+----------+---------
id | integer | | |
name | character varying(100) | | |
department | character varying(50) | | |
created_date | timestamp without time zone | | |
Indexes:
"idx_mv_employees_id" UNIQUE, btree (id)
postgres=>
postgres=> SELECT definition FROM pg_matviews WHERE matviewname = 'mv_employees';
definition
--------------------------------
SELECT fdw_employees.id, +
fdw_employees.name, +
fdw_employees.department, +
fdw_employees.created_date+
FROM fdw_employees;
(1 row)
postgres=>
3.データも見えました
postgres=> select * from mv_employees;
id | name | department | created_date
----+---------------+-------------+---------------------
1 | Tanaka Taro | Sales | 2026-03-20 03:42:07
2 | Suzuki Hanako | Engineering | 2026-03-20 03:42:07
3 | Sato Jiro | Marketing | 2026-03-20 03:42:07
(3 rows)
postgres=>
日本語テーブルのMview
1.Mviewを作成します
postgres=> CREATE MATERIALIZED VIEW mv_employees_jp AS
postgres-> SELECT employee_id, name, department, created_date FROM fdw_employees_jp;
SELECT 3
postgres=>
postgres=> CREATE UNIQUE INDEX idx_mv_employees_jp_id ON mv_employees_jp(employee_id);
CREATE INDEX
postgres=>
2.定義を確認します
postgres=> \d mv_employees_jp
Materialized view "public.mv_employees_jp"
Column | Type | Collation | Nullable | Default
--------------+-----------------------------+-----------+----------+---------
employee_id | integer | | |
name | character varying(100) | | |
department | character varying(50) | | |
created_date | timestamp without time zone | | |
Indexes:
"idx_mv_employees_jp_id" UNIQUE, btree (employee_id)
postgres=>
postgres=> SELECT definition FROM pg_matviews WHERE matviewname = 'mv_employees_jp';
definition
---------------------------------------
SELECT fdw_employees_jp.employee_id,+
fdw_employees_jp.name, +
fdw_employees_jp.department, +
fdw_employees_jp.created_date +
FROM fdw_employees_jp;
(1 row)
postgres=>
3.データも見えました
postgres=> SELECT employee_id, name, department, created_date FROM fdw_employees_jp;
employee_id | name | department | created_date
-------------+----------+------------+---------------------
101 | 山田一郎 | 総務部 | 2026-03-20 03:34:17
102 | 高橋美月 | 人事部 | 2026-03-20 03:34:17
103 | 渡辺健太 | 経理部 | 2026-03-20 03:34:17
(3 rows)
postgres=>
Mviewリフレッシュの確認
英語カラムのテーブル
データの登録(Oracle)
1.データを登録します
SQL> INSERT INTO employees VALUES (4, 'Yamada Ichiro', 'Finance', SYSDATE);
COMMIT;
1 row created.
SQL>
Commit complete.
2.データを確認します。登録されました
SQL> select * from employees;
ID NAME DEPARTMENT CREATED_DATE
---------- ---------------------------------------------------------------------------------------------------- -------------------------------------------------- -------------------
1 Tanaka Taro Sales 2026/03/20 03:42:07
2 Suzuki Hanako Engineering 2026/03/20 03:42:07
3 Sato Jiro Marketing 2026/03/20 03:42:07
4 Yamada Ichiro Finance 2026/03/20 04:34:35
SQL>
データの確認(PostgreSQL 外部テーブル)
1.外部テーブルでデータが確認できました
postgres=> select * from fdw_employees;
id | name | department | created_date
----+---------------+-------------+---------------------
1 | Tanaka Taro | Sales | 2026-03-20 03:42:07
2 | Suzuki Hanako | Engineering | 2026-03-20 03:42:07
3 | Sato Jiro | Marketing | 2026-03-20 03:42:07
4 | Yamada Ichiro | Finance | 2026-03-20 04:34:35
(4 rows)
postgres=>
リフレッシュの確認(PostgreSQL Mview)
1.リフレッシュ前のデータを確認します。想定通り、Mview上でデータは見えません
postgres=> select * from mv_employees;
id | name | department | created_date
----+---------------+-------------+---------------------
1 | Tanaka Taro | Sales | 2026-03-20 03:42:07
2 | Suzuki Hanako | Engineering | 2026-03-20 03:42:07
3 | Sato Jiro | Marketing | 2026-03-20 03:42:07
(3 rows)
postgres=>
2.リフレッシュします
postgres=> REFRESH MATERIALIZED VIEW CONCURRENTLY mv_employees;
REFRESH MATERIALIZED VIEW
postgres=>
3.リフレッシュ後のデータを確認します。1行増えました
postgres=> select * from mv_employees;
id | name | department | created_date
----+---------------+-------------+---------------------
1 | Tanaka Taro | Sales | 2026-03-20 03:42:07
2 | Suzuki Hanako | Engineering | 2026-03-20 03:42:07
3 | Sato Jiro | Marketing | 2026-03-20 03:42:07
4 | Yamada Ichiro | Finance | 2026-03-20 04:34:35
(4 rows)
postgres=>
日本語カラムのテーブル
データの登録(Oracle)
1.データを登録します
INSERT INTO employees_jp VALUES (104, '中村美咲', '開発部', SYSDATE);
COMMIT;
2.データを確認します。登録されました
SQL> select * from employees_jp
2 ;
社員ID 氏名 部署 作成日
---------- ---------------------------------------------------------------------------------------------------- -------------------------------------------------- -------------------
104 中村美咲 開発部 2026/03/20 04:38:18
101 山田一郎 総務部 2026/03/20 03:34:17
102 高橋美月 人事部 2026/03/20 03:34:17
103 渡辺健太 経理部 2026/03/20 03:34:17
SQL>
データの確認(PostgreSQL 外部テーブル)
1.外部テーブルでデータが確認できました
postgres=> select * from fdw_employees_jp;
employee_id | name | department | created_date
-------------+----------+------------+---------------------
104 | 中村美咲 | 開発部 | 2026-03-20 04:38:18
101 | 山田一郎 | 総務部 | 2026-03-20 03:34:17
102 | 高橋美月 | 人事部 | 2026-03-20 03:34:17
103 | 渡辺健太 | 経理部 | 2026-03-20 03:34:17
(4 rows)
postgres=>
リフレッシュの確認(PostgreSQL Mview)
1.リフレッシュ前のデータを確認します。想定通り、Mview上でデータは見えません
postgres=> select * from mv_employees_jp;
employee_id | name | department | created_date
-------------+----------+------------+---------------------
101 | 山田一郎 | 総務部 | 2026-03-20 03:34:17
102 | 高橋美月 | 人事部 | 2026-03-20 03:34:17
103 | 渡辺健太 | 経理部 | 2026-03-20 03:34:17
(3 rows)
postgres=>
2.リフレッシュします
postgres=> REFRESH MATERIALIZED VIEW CONCURRENTLY mv_employees_jp;
REFRESH MATERIALIZED VIEW
postgres=>
3.リフレッシュ後のデータを確認します。1行増えました
postgres=> select * from mv_employees_jp;
employee_id | name | department | created_date
-------------+----------+------------+---------------------
101 | 山田一郎 | 総務部 | 2026-03-20 03:34:17
102 | 高橋美月 | 人事部 | 2026-03-20 03:34:17
103 | 渡辺健太 | 経理部 | 2026-03-20 03:34:17
104 | 中村美咲 | 開発部 | 2026-03-20 04:38:18
(4 rows)
postgres=>
考察
oracle_fdwのサブクエリ方式でカラム名をマッピングした。サブクエリ方式ではschemaオプションと併用できない点に注意が必要でした。
まだまだわかっていないことも多いので、機会があれば今後もoracle_fdwの検証を行いたいと思います。
参考

