8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

oracle-ai-ready-data Skill 第2回: Databaseのメタデータを整備してAI Readyスコアを0.22から0.97へ改善し、Select AIで確認してみてみた

8
Last updated at Posted at 2026-07-27

oracle-ai-ready-data Skill 第1回では、サンプルのHRスキーマを対象にoracle-ai-ready-data SkillでAI Ready評価を行いました。HRスキーマはテーブル名やカラム名、主キー・外部キーなどが比較的分かりやすく整備されていたため、コメント必須ゲートを通過し、AIから利用しやすい状態に近いことを確認できました。

一方、実際のシステムでは、データそのものに問題がなくても、テーブルやカラムの説明、主キー・外部キー、更新日時、データの出所、統計情報などが十分に整備されていないケースがあります。このような状態では、人間は経験から意味を推測できても、AIは業務上の意味や表同士の関係を正しく判断しにくくなります。

今回は、行データの一意性と参照整合性はあらかじめ満たしつつ、AI利用に必要なメタデータだけを意図的に欠落させたBAD_AI_READYスキーマを作成します。その後、Skillが生成した改善候補を今回のデータモデルに合わせてレビューし、改善SQLを実行して評価結果がどのように変わるかを確認します。最後に、整備したコメントとPK/FKをSelect AIが自然言語からのSQL生成に利用できるかも確認してみてみます。

oracle-ai-ready-data Skill は、Oracle Databaseのコメント、制約、統計、鮮度、出所、権限などのメタデータを確認し、AIから利用しやすい状態かを0.00〜1.00で評価します。

AIReady絵.jpg

ということで、未Readyな状態からAI Ready候補へ改善する一連の流れを、実際にしてみてみます。

今回の確認ポイントは次のとおりです。

確認内容 見るポイント
改善前評価 Mandatory comment gateがfailになるか
改善SQL コメント、PK/FK、鮮度、出所、統計、権限を改善できるか
改善後評価 Mandatory gateと各coverageが改善するか
Select AI コメントや制約を使い、適切な表選択・JOIN・集計ができるか
LLMによる差 同じメタデータ・同じ日本語でも、モデル変更で生成SQLと回答が変わるか

本記事のAI Readyは、データ・ディクショナリから確認できるメタデータ上の準備状況を指します。実データの業務上の正しさ、個人情報の利用可否、法令遵守、生成SQLの完全性を保証するものではありません。

● Agenda

■ BAD_AI_READY スキーマ作成

今回用の検証スキーマは、GitHub Releaseで公開している再現パッケージを使用します。DDL、CSVデータ、改善SQL、検証SQL、Select AI用プロンプトをまとめているため、同じ構成を繰り返し作成できます。

BAD_AI_READY Part 2 ダウンロード: bad_ai_ready_part2-v1.0.0.zip

00_admin_create_schema.sqlは既存のBAD_AI_READYユーザーを削除して再作成します。必ず検証用データベースまたは使い捨て可能なスキーマで実行してください。

● パッケージの設計

作成されるのは次の8表です。重複キー、NULLキー、孤児レコードは含めておらず、改善SQLからPK/FKをそのままENABLE VALIDATEで追加できるテストデータにしています。

行数 今回の確認ポイント
RAW_CUSTOMERS 50 顧客状態、国コード、文字列日時、PII候補列の説明不足
RAW_ORDERS 100 注文日・金額が文字列であり、顧客との関係が未定義
RAW_ORDER_LINES 200 数量・単価・割引率が文字列であり、注文との関係が未定義
SUPPORT_TICKETS 30 状態・重大度コードと顧客との関係、機微情報候補の説明不足
CUSTOMER_FEATURES 50 離反スコア・生涯価値の意味、顧客との関係、出所が未定義
AI_DOCUMENTS 12 CLOB本文はあるが、コメント、出所、鮮度、VECTOR列が未整備
ORPHAN_REGIONS 6 実体は国コード参照マスタだが、名前だけでは業務用途が分かりにくい
EMPTY_EXPORT 0 空表でもコメントや主キーなどのメタデータ評価対象になることを確認

CSVは合計448行です。改善前は8表・52列で、改善SQLによって各表へUPDATED_ATSOURCE_SYSTEMを追加するため、改善後は68列になります。

行データは次の条件を満たしています。

  • PK候補はNULLなし・重複なし
  • FK候補はすべて参照先あり
  • 日付、金額、数量、状態コードは統一した文字列形式
  • メールアドレス、電話番号、識別番号、URIはすべて合成値

一方、メタデータは意図的に次の状態にしています。

テーブルコメント:0件
カラムコメント:0件
PK、FK、UNIQUE、CHECK:0件
鮮度列:0件
`SOURCE_SYSTEM`などの出所メタデータ列:0件
VECTOR列:0件
オプティマイザ統計:評価直前に削除
PUBLIC SELECT:任意で3表へ付与

つまり、今回は「壊れたデータを修復する」のではなく、正しく関連付けられるデータに対して、AIが意味を理解するためのメタデータを追加することに焦点を当てます。

● スキーマ作成とCSVロード

1) ZIPを展開してパッケージへ移動

SQLclのLOADコマンドはdata/*.csvを相対パスで参照するため、展開したパッケージのルートで作業します。

unzip bad_ai_ready_part2-v1.0.0.zip
cd bad_ai_ready_part2

2) ADMINでBAD_AI_READYスキーマを作成

Autonomous AI DatabaseへADMINで接続し、検証用のBAD_AI_READYユーザーを作成します。パスワードはSQLcl上で対話入力するため、SQLファイルには保存されません。

00_admin_create_schema.sql
-- Run as ADMIN, SYS, or a user that can CREATE USER.
-- Usage in SQLcl:
--   @00_admin_create_schema.sql
-- The password is requested interactively and is not echoed.
--
-- This script drops BAD_AI_READY if it already exists.
-- Use only in an isolated test database or disposable schema.

set define on
set verify off
set feedback on
set serveroutput on

whenever sqlerror continue none
drop user bad_ai_ready cascade;
whenever sqlerror exit sql.sqlcode rollback

accept bad_ai_ready_password char prompt 'Enter a strong password for BAD_AI_READY: ' hide

create user bad_ai_ready identified by "&&bad_ai_ready_password"
  account unlock;

declare
  l_tablespace varchar2(128);
begin
  select default_tablespace
    into l_tablespace
    from dba_users
   where username = 'BAD_AI_READY';

  execute immediate
    'alter user bad_ai_ready quota unlimited on "' ||
    replace(l_tablespace, '"', '""') || '"';

  dbms_output.put_line('Quota granted on default tablespace: ' || l_tablespace);
end;
/

grant create session to bad_ai_ready;
grant create table to bad_ai_ready;
grant create view to bad_ai_ready;
grant create sequence to bad_ai_ready;

undefine bad_ai_ready_password

prompt BAD_AI_READY user created.
prompt Reconnect as BAD_AI_READY and run 01_create_bad_tables.sql.
sql admin/<ADMIN_PASSWORD>@adb_high @00_admin_create_schema.sql

実行後はBAD_AI_READYへ接続し直します。

3) BAD_AI_READYでテーブルDDLを実行

01_create_bad_tables.sqlでは、コメント、主キー、外部キー、鮮度列、出所列を持たない8表を作成します。ここで不足を意図的に作ることで、後のSkill評価と改善SQLの効果を比較しやすくします。

sql bad_ai_ready/<BAD_AI_READY_PASSWORD>@adb_high @01_create_bad_tables.sql

4) CSVをインポート

CSVロードにはSQLclのLOADコマンドを使用します。ヘッダー付きUTF-8のCSVを既存表へロードし、8表合計448行を登録します。

@02_load_csv.sql

5) 任意でPUBLIC権限を追加

Compliantの評価で広いデータアクセス権限が検出されることを確認するため、次の3表へ意図的にPUBLIC SELECTを付与できます。

  • RAW_CUSTOMERS
  • RAW_ORDERS
  • SUPPORT_TICKETS
@03_optional_public_grants.sql

この手順は任意ですが、実行すると改善SQLのREVOKEまで含めたBefore/Afterを確認できます。

6) 評価直前に統計情報を削除

Autonomous AI Databaseでは統計情報が自動収集される場合があります。初回評価で統計情報が未整備な状態を再現しやすくするため、Skill実行の直前に削除します。

@04_delete_stats_before_scan.sql

統計情報は自動収集のタイミングによって一部が再作成される場合があります。そのため、総合スコアの絶対値だけではなく、Mandatory gateや各coverageの変化を中心に確認します。

■ 改善前の oracle-ai-ready-data 評価

BAD_AI_READYの準備ができたので、まずは改善前の状態をscan Profileで評価します。oracle_ai_ready_collect.sqlでデータ・ディクショナリのメタデータを収集し、Pythonスクリプトでレポートと改善SQL候補を生成します。

Skillは実データの全行を読み取って判定するのではなく、主にコメント、制約、統計、列型、鮮度・出所候補、権限などを評価します。そのため、今回のように行データが整合していても、メタデータが不足していれば低い評価になります。

GitHubからリポジトリをダウンロードし、Oracle SQLclを実行するクライアントへ配置します。

Oracle AI Ready Data Skill - GitHub

ディレクトリ構成は以下のようになっています。

oracle-ai-ready-data/
├── README.md
├── SKILL.md
├── scripts/
│   ├── oracle_ai_ready_collect.sql
│   ├── oracle_ai_feature_collect.sql
│   ├── score_oracle_ai_ready_scan.py
│   └── score_oracle_ai_feature_readiness.py
├── profiles/
│   ├── scan.yaml
│   ├── rag.yaml
│   └── feature-readiness.yaml
├── references/
└── examples/

● SQLclでメタデータ収集

oracle-ai-ready-dataでは、SQLclで収集した.outファイルを入力として、同じメタデータから評価レポートと改善SQLを生成します。収集と採点を分離しているため、収集結果を保存して別のProfileで再評価することもできます。

1) ディレクトリ移動

cd oracle-ai-ready-data-main

2) 改善前メタデータを収集
メタデータ .outファイルが出力されます。

今回の環境用に 引数は次を使用します。

 schema: admin
 schema_owner:  BAD_AI_READY
oracle-ai-ready-data実行
sql -s <schema>/<ADMIN_PASSWORD>@adb_high \
  @scripts/oracle_ai_ready_collect.sql <schema_owner> % scan

3) メタデータ .outファイル確認
このファイルを使用してレポート整形することができます。
レポートファイル名は、oracle-ai-ready-data 実行した引数を利用して生成されます。

.outファイル確認
ls -ltr
・・・
-rw-r--r-- 1 shirok staff 11988 Jul 21 13:05 oracle_ai_ready_scan_BAD_AI_READY_scan.out

4) 改善前レポートと改善SQL候補を生成

レポートとチューニングSQL生成
python3 scripts/score_oracle_ai_ready_scan.py \
  oracle_ai_ready_scan_BAD_AI_READY_scan.out \
  --profile scan \
  --language ja \
  --output bad_ai_ready_scan_before_report.md \
  --html-output bad_ai_ready_scan_before_report.html \
  --sql-output bad_ai_ready_scan_before_improvement.sql

5) 生成ファイルを確認
次の3ファイルが生成されていることを確認します。.outは収集したメタデータ、.mdは評価結果、.sqlは不足項目に対する改善候補です。

.md マークダウンファイル: AI Ready評価レポート
.html HTMLファイル: 人が確認しやすいAI Ready評価レポート
.sqlファイル: AI Ready改善SQL候補
レポートとチューニングSQL生成確認
$ ls -ltr
・・・
-rw-r--r-- 1 shirok staff 11988 Jul 21 13:05 oracle_ai_ready_scan_BAD_AI_READY_scan.out
-rw-r--r-- 1 shirok staff 32955 Jul 21 13:10 bad_ai_ready_scan_before_report.md
-rw-r--r-- 1 shirok staff 35070 Jul 21 13:10 bad_ai_ready_scan_before_report.html
-rw-r--r-- 1 shirok staff 16655 Jul 21 13:10 bad_ai_ready_scan_before_improvement.sql

● HTMLレポートをブラウザで確認

--html-outputを指定すると、Markdownと同じ評価内容をカード、ステータス・バッジ、プログレスバーで確認できる自己完結型のHTMLレポートも生成されます。CSSはHTML内に埋め込まれているため、外部CDNやJavaScriptを使わず、ローカルのブラウザで開けます。

HTMLレポートを開く例(macOS)
open bad_ai_ready_scan_before_report.html

MarkdownはGitHubやQiitaでの共有、HTMLはレビュー会やブラウザでの確認に使い分けられます。

■ 改善前レポート結果

今回の実行では総合スコアが0.22、Mandatory comment gateとComment quality reviewがともにfailとなりました。さらに、数値や日付として扱う可能性がある文字列型カラムが11件検出されました。統計情報はAutonomous AI Databaseの自動収集タイミングによって一部残ることがありますが、コメント、PK/FK、鮮度、出所など、今回意図的に欠落させた項目は期待どおり検出されています。

レポート全文は長いため、以下の折りたたみ内へ掲載します。

bad_ai_ready_scan_before_report.md 内容(確認はここをクリック)

Oracle Database AI Ready 評価レポート

1. エグゼクティブサマリー

  • 総合スコア: 0.22 / 1.00
  • Profile: scan
  • Mandatory comment gate: fail
  • Comment quality review: fail
  • Semantic type warnings: 11件
  • 結論: 必須コメントゲート未達のため、要求ポリシー上は未Ready
  • コメント有無チェックは必須条件です。コメント品質とSemantic type mismatchは初期実装では警告であり、既存スコアには影響しません。

2. スコープと前提

項目
Schema BAD_AI_READY
Table pattern %
Profile scan
評価対象テーブル数 8
評価対象カラム数 52
SQLcl spool oracle_ai_ready_scan_BAD_AI_READY_scan.out
Scan timestamp 2026-07-21T04:45:57.267992 +00:00
注意事項 ALL_* dictionary viewsで見えるメタデータを評価します。実データ値、業務上の正しさ、法令遵守は別途レビューが必要です。

3. 評価項目の説明

Dimension Weight 何を評価しているか なぜ重要か
Clean 20.0% 主キー、制約、統計情報があり、AI処理の前提となる構造的な信頼性を確認します。 キーや統計情報が不足すると、根拠行の特定、結合、品質確認が不安定になります。
Contextual 25.0% テーブル/カラムコメントとリレーション定義により、データの意味が説明できるかを確認します。 AIが列名だけから意味を推測すると誤解しやすいため、コメントを必須ゲートにしています。
Consumable 15.0% AIやRAGパイプラインが利用しやすいテキスト列、VECTOR列、安定ID、ドキュメントを確認します。 検索対象、根拠、embedding管理方法が曖昧だと、RAG/agentの回答品質が安定しません。
Current 15.0% 更新日時などの鮮度列と最近の統計情報があり、データの新しさを説明できるかを確認します。 古いデータや更新時点不明のデータは、AI回答の鮮度リスクになります。
Correlated 15.0% 外部キー、主キー、source/update系メタデータにより、他テーブルや元データと関連付けられるかを確認します。 関連が宣言されていないと、AIが表間のつながりを誤解したり、根拠追跡が弱くなります。
Compliant 10.0% 機微情報らしい列名、コメント有無、広い権限付与候補を検出し、レビュー可能性を確認します。 この評価は法令遵守を保証しませんが、AI利用前のセキュリティ/プライバシーレビュー対象を明確にします。

4. スコアカード

Dimension Weight Score 主な根拠
Clean 20.0% 0.45 PK 0.0%, table stats 87.5%, column stats 94.2%, constraints 0.0%
Contextual 25.0% 0.00 table comments 0.0%, column comments 0.0%, relationships 0.0%
Consumable 15.0% 0.35 text-bearing tables 100.0%, vector tables 0.0%, documentation 0.0%, PK 0.0%
Current 15.0% 0.35 freshness columns 0.0%, recent stats 87.5%
Correlated 15.0% 0.00 FK 0.0%, source metadata 0.0%, PK 0.0%
Compliant 10.0% 0.28 sensitive documented 0.0%, broad data grant absence 62.5%

5. メトリクス詳細

Metric Value Status 説明
Table comment coverage 0.0% fail コメントが設定されている評価対象テーブルの割合です。100%でない場合は必須ゲートがfailです。
Column comment coverage 0.0% fail コメントが設定されている評価対象カラムの割合です。100%でない場合は必須ゲートがfailです。
PK coverage 0.0% 要改善 有効な主キーがあるテーブルの割合です。AI回答の根拠行を安定して参照するために重要です。
FK coverage 0.0% 要改善 外部キーを持つ、または外部キー関係に参加するテーブルの割合です。表間の関連を安全に扱うための指標です。
Relationship coverage 0.0% 要改善 主キーまたは外部キーのいずれかを持つテーブルの割合です。データモデルの説明可能性を見ます。
Constraint coverage 0.0% 要改善 主キー、一意、外部キー、CHECK制約のいずれかがあるテーブルの割合です。構造的な品質管理の指標です。
Table stats coverage 87.5% 良好 LAST_ANALYZEDが入っているテーブルの割合です。統計情報が未取得だとデータ状態の確認が弱くなります。
Column stats coverage 94.2% 良好 LAST_ANALYZEDが入っているカラムの割合です。列分布やNULL傾向の評価に使います。
Recent stats coverage 87.5% 良好 統計情報が最近取得されているテーブルの割合です。既定では90日以内をrecentと見なします。
Freshness coverage 0.0% 要改善 UPDATED_ATやLAST_UPDATE_DATEなど、鮮度を示す列があるテーブルの割合です。
Source metadata coverage 0.0% 要改善 SOURCE_SYSTEM、BATCH_ID、CREATED_BYなど、出所や更新者を示す列があるテーブルの割合です。
Text-bearing table coverage 100.0% 参考 RAG候補となるテキスト列を持つテーブルの割合です。検索対象テキストの有無を確認します。
Vector table coverage 0.0% 参考 VECTOR型またはembedding候補を持つテーブルの割合です。embeddingを外部管理している場合は設計書で補足してください。
Sensitive candidate documentation 0.0% 要改善 機微情報候補列のうちコメントがある列の割合です。列名ベース推定なので人間の分類が必要です。
Broad data grant absence 62.5% 要改善 PUBLICなど広い相手へのデータアクセス権限が検出されなかった割合です。高いほどリスクが低い見立てです。
Table comment quality coverage 0.0% fail コメント本文がplaceholder、短すぎる説明、汎用文ではない割合です。初期実装では警告のみです。
Column comment quality coverage 0.0% fail コメント本文がplaceholder、短すぎる説明、汎用文ではない割合です。初期実装では警告のみです。

6. Mandatory comment gate

Check Coverage Result Required action
Table comments 0.0% fail Missing 8 table comments
Column comments 0.0% fail Missing 52 column comments

7. 主要な発見事項

High priority

  • Mandatory comment gate が fail です。table comment 欠落 8 件、column comment 欠落 52 件があります。
  • 主キー未検出のテーブルが 8 件あります。RAG/agent応答の根拠行を安定して参照しづらくなります。
  • PUBLICなど広いデータアクセス権限候補が 3 件あります。AI利用前に公開範囲を確認してください。

Medium priority

  • 統計情報が未取得または古いテーブルが 1 件あります。Clean/Current score の主な減点要因です。
  • 鮮度を示す日時列が未検出のテーブルが 8 件あります。データの新しさを説明しづらくなります。
  • 機微情報候補列が 10 件あります。列名ベースの推定のため、業務オーナーによる分類が必要です。

Low priority / manual review

  • VECTOR型カラムは未検出です。embeddingを別スキーマや外部サービスで管理している場合は設計書に明記してください。

8. コメント品質

項目
Table comment quality coverage 0.0%
Column comment quality coverage 0.0%
Placeholder comments 0
Too-short comments 0
Generic/name-only comments 0
Repeated generic groups 0
Object Issue Current comment
BAD_AI_READY.AI_DOCUMENTS missing -
BAD_AI_READY.CUSTOMER_FEATURES missing -
BAD_AI_READY.EMPTY_EXPORT missing -
BAD_AI_READY.ORPHAN_REGIONS missing -
BAD_AI_READY.RAW_CUSTOMERS missing -
BAD_AI_READY.RAW_ORDERS missing -
BAD_AI_READY.RAW_ORDER_LINES missing -
BAD_AI_READY.SUPPORT_TICKETS missing -
BAD_AI_READY.AI_DOCUMENTS.BODY_TEXT missing -
BAD_AI_READY.AI_DOCUMENTS.CHUNK_NUMBER missing -
BAD_AI_READY.AI_DOCUMENTS.DOC_ID missing -
BAD_AI_READY.AI_DOCUMENTS.EMBEDDING_BLOB_TXT missing -
BAD_AI_READY.AI_DOCUMENTS.LIFECYCLE_STATE missing -
BAD_AI_READY.AI_DOCUMENTS.ORIGIN_URI missing -
BAD_AI_READY.AI_DOCUMENTS.TITLE_TXT missing -
BAD_AI_READY.CUSTOMER_FEATURES.CHURN_SCORE_TXT missing -
BAD_AI_READY.CUSTOMER_FEATURES.CUSTOMER_ID missing -
BAD_AI_READY.CUSTOMER_FEATURES.FEATURE_NOTES missing -
BAD_AI_READY.CUSTOMER_FEATURES.LIFETIME_VALUE_TXT missing -
BAD_AI_READY.CUSTOMER_FEATURES.SEGMENT_CODE missing -
BAD_AI_READY.EMPTY_EXPORT.EXPORT_ID missing -
BAD_AI_READY.EMPTY_EXPORT.EXPORT_NAME missing -
BAD_AI_READY.EMPTY_EXPORT.PAYLOAD missing -
BAD_AI_READY.ORPHAN_REGIONS.COUNTRY_CODE missing -
BAD_AI_READY.ORPHAN_REGIONS.REGION_NAME missing -
BAD_AI_READY.ORPHAN_REGIONS.RISK_TIER_TXT missing -
BAD_AI_READY.RAW_CUSTOMERS.BIRTHDATE_TXT missing -
BAD_AI_READY.RAW_CUSTOMERS.COUNTRY_CODE missing -
BAD_AI_READY.RAW_CUSTOMERS.CUSTOMER_ID missing -
BAD_AI_READY.RAW_CUSTOMERS.EMAIL missing -
BAD_AI_READY.RAW_CUSTOMERS.FULL_NAME missing -
BAD_AI_READY.RAW_CUSTOMERS.LAST_PURCHASE_AMT missing -
BAD_AI_READY.RAW_CUSTOMERS.NOTES missing -
BAD_AI_READY.RAW_CUSTOMERS.PHONE missing -
BAD_AI_READY.RAW_CUSTOMERS.SIGNUP_WHEN_TXT missing -
BAD_AI_READY.RAW_CUSTOMERS.SSN missing -
BAD_AI_READY.RAW_CUSTOMERS.STATUS_TXT missing -
BAD_AI_READY.RAW_ORDERS.AMOUNT_TXT missing -
BAD_AI_READY.RAW_ORDERS.CURRENCY_CODE missing -
BAD_AI_READY.RAW_ORDERS.CUSTOMER_ID missing -
BAD_AI_READY.RAW_ORDERS.ORDER_ID missing -
BAD_AI_READY.RAW_ORDERS.ORDER_PAYLOAD missing -
BAD_AI_READY.RAW_ORDERS.ORDER_TIME_TXT missing -
BAD_AI_READY.RAW_ORDERS.PAYMENT_CARD_HINT missing -
BAD_AI_READY.RAW_ORDERS.SHIPPING_POSTAL_CODE missing -
BAD_AI_READY.RAW_ORDER_LINES.DISCOUNT_TXT missing -
BAD_AI_READY.RAW_ORDER_LINES.LINE_COMMENT missing -
BAD_AI_READY.RAW_ORDER_LINES.LINE_NO missing -
BAD_AI_READY.RAW_ORDER_LINES.ORDER_ID missing -
BAD_AI_READY.RAW_ORDER_LINES.QUANTITY_TXT missing -
BAD_AI_READY.RAW_ORDER_LINES.SKU missing -
BAD_AI_READY.RAW_ORDER_LINES.UNIT_PRICE_TXT missing -
BAD_AI_READY.SUPPORT_TICKETS.AGENT_EMAIL missing -
BAD_AI_READY.SUPPORT_TICKETS.CUSTOMER_ID missing -
BAD_AI_READY.SUPPORT_TICKETS.PROBLEM_DESCRIPTION missing -
BAD_AI_READY.SUPPORT_TICKETS.REQUESTER_PHONE missing -
BAD_AI_READY.SUPPORT_TICKETS.RESOLUTION_TEXT missing -
BAD_AI_READY.SUPPORT_TICKETS.SEVERITY_TXT missing -
BAD_AI_READY.SUPPORT_TICKETS.TICKET_ID missing -
BAD_AI_READY.SUPPORT_TICKETS.TICKET_STATUS missing -

9. Semantic type mismatch

文字列型ですが、列名またはコメントから数値・日付として扱われる可能性がある列です。推定結果のため、自動的な型変更は行いません。

Column DB type 推定される意味 根拠 推奨対応
BAD_AI_READY.CUSTOMER_FEATURES.CHURN_SCORE_TXT VARCHAR2 NUMBER name: SCORE NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.CUSTOMER_FEATURES.LIFETIME_VALUE_TXT VARCHAR2 NUMBER name: VALUE NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_CUSTOMERS.BIRTHDATE_TXT VARCHAR2 DATE/TIMESTAMP name: BIRTHDATE DATE/TIMESTAMP列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_CUSTOMERS.LAST_PURCHASE_AMT VARCHAR2 NUMBER name: AMT NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_CUSTOMERS.SIGNUP_WHEN_TXT VARCHAR2 DATE/TIMESTAMP name: WHEN DATE/TIMESTAMP列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDERS.AMOUNT_TXT VARCHAR2 NUMBER name: AMOUNT NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDERS.ORDER_TIME_TXT VARCHAR2 DATE/TIMESTAMP name: TIME DATE/TIMESTAMP列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDER_LINES.DISCOUNT_TXT VARCHAR2 NUMBER name: DISCOUNT NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDER_LINES.QUANTITY_TXT VARCHAR2 NUMBER name: QUANTITY NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDER_LINES.UNIT_PRICE_TXT VARCHAR2 NUMBER name: PRICE NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.SUPPORT_TICKETS.SEVERITY_TXT VARCHAR2 NUMBER name: SEVERITY NUMBER列、仮想列、または型付きAI用Viewを検討してください。

10. 改善SQLの考え方

SQLカテゴリ 理由 目的 実行前確認
COMMENT ON TABLE / COLUMN コメント欠落はmandatory gateとContextual scoreを下げます。 業務意味、粒度、単位、NULL意味、機微性を明文化します。 TODO文を実説明に置換し、業務オーナー承認後に実行します。
Comment quality review コメントが存在してもplaceholderや汎用文ではAIへ十分な意味を伝えられません。 実際の業務説明へ置き換えます。 自動上書きはせず、人間がレビューします。
Semantic type review 文字列型に数値・日付が保存されるとNL2SQLで暗黙変換や文字列比較が発生します。 型付き列、仮想列、AI用Viewを検討します。 自動ALTERは生成しません。データとアプリ影響を確認します。
DBMS_STATS.GATHER_TABLE_STATS LAST_ANALYZED未設定/古い統計はClean/Current scoreを下げます。 統計情報を収集します。 大規模表ではDBA確認が必要です。
PRIMARY KEY / freshness column キーや鮮度列の不足は根拠追跡や新しさ説明を弱くします。 根拠行の特定と鮮度説明を可能にします。 テンプレートのため設計レビューが必要です。
REVOKE候補 広いデータ権限はAI利用前の公開範囲確認が必要です。 不要な公開を減らします。 依存利用者への影響を確認します。
-- Remediation: missing table comments
-- Reason: テーブルコメントがないため、Contextual score と mandatory comment gate が低下します。
-- Purpose: テーブルの業務目的、粒度、更新頻度、AI利用時の注意点を明文化します。
-- Review: TODOコメントを業務オーナーが実際の説明に置き換えてから実行してください。
COMMENT ON TABLE "BAD_AI_READY"."AI_DOCUMENTS" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.AI_DOCUMENTS.';
COMMENT ON TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.CUSTOMER_FEATURES.';
COMMENT ON TABLE "BAD_AI_READY"."EMPTY_EXPORT" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.EMPTY_EXPORT.';
COMMENT ON TABLE "BAD_AI_READY"."ORPHAN_REGIONS" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.ORPHAN_REGIONS.';
COMMENT ON TABLE "BAD_AI_READY"."RAW_CUSTOMERS" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.RAW_CUSTOMERS.';
COMMENT ON TABLE "BAD_AI_READY"."RAW_ORDERS" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.RAW_ORDERS.';
COMMENT ON TABLE "BAD_AI_READY"."RAW_ORDER_LINES" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.RAW_ORDER_LINES.';
COMMENT ON TABLE "BAD_AI_READY"."SUPPORT_TICKETS" IS 'TODO: describe business purpose, grain, refresh cadence, owner, and AI usage guidance for BAD_AI_READY.SUPPORT_TICKETS.';

-- Remediation: missing column comments
-- Reason: カラムコメントがないため、AIが列の意味、単位、NULLの意味、機微性を誤解する可能性があります。
-- Purpose: 各カラムの意味、形式、許容値、NULLの扱い、出所、機微性を明文化します。
-- Review: TODOコメントを業務オーナーが実際の説明に置き換えてから実行してください。
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."BODY_TEXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.BODY_TEXT.';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."CHUNK_NUMBER" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.CHUNK_NUMBER.';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."DOC_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.DOC_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."EMBEDDING_BLOB_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.EMBEDDING_BLOB_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."LIFECYCLE_STATE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.LIFECYCLE_STATE.';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."ORIGIN_URI" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.ORIGIN_URI.';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."TITLE_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.AI_DOCUMENTS.TITLE_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."CHURN_SCORE_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.CUSTOMER_FEATURES.CHURN_SCORE_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."CUSTOMER_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.CUSTOMER_FEATURES.CUSTOMER_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."FEATURE_NOTES" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.CUSTOMER_FEATURES.FEATURE_NOTES.';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."LIFETIME_VALUE_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.CUSTOMER_FEATURES.LIFETIME_VALUE_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."SEGMENT_CODE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.CUSTOMER_FEATURES.SEGMENT_CODE.';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."EXPORT_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.EMPTY_EXPORT.EXPORT_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."EXPORT_NAME" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.EMPTY_EXPORT.EXPORT_NAME.';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."PAYLOAD" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.EMPTY_EXPORT.PAYLOAD.';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."COUNTRY_CODE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.ORPHAN_REGIONS.COUNTRY_CODE.';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."REGION_NAME" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.ORPHAN_REGIONS.REGION_NAME.';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."RISK_TIER_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.ORPHAN_REGIONS.RISK_TIER_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."BIRTHDATE_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.BIRTHDATE_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."COUNTRY_CODE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.COUNTRY_CODE.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."CUSTOMER_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.CUSTOMER_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."EMAIL" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.EMAIL.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."FULL_NAME" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.FULL_NAME.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."LAST_PURCHASE_AMT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.LAST_PURCHASE_AMT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."NOTES" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.NOTES.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."PHONE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.PHONE.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."SIGNUP_WHEN_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.SIGNUP_WHEN_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."SSN" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.SSN.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."STATUS_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_CUSTOMERS.STATUS_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."AMOUNT_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.AMOUNT_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."CURRENCY_CODE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.CURRENCY_CODE.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."CUSTOMER_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.CUSTOMER_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."ORDER_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.ORDER_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."ORDER_PAYLOAD" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.ORDER_PAYLOAD.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."ORDER_TIME_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.ORDER_TIME_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."PAYMENT_CARD_HINT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.PAYMENT_CARD_HINT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."SHIPPING_POSTAL_CODE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDERS.SHIPPING_POSTAL_CODE.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."DISCOUNT_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.DISCOUNT_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."LINE_COMMENT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.LINE_COMMENT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."LINE_NO" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.LINE_NO.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."ORDER_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.ORDER_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."QUANTITY_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.QUANTITY_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."SKU" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.SKU.';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."UNIT_PRICE_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.RAW_ORDER_LINES.UNIT_PRICE_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."AGENT_EMAIL" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.AGENT_EMAIL.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."CUSTOMER_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.CUSTOMER_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."PROBLEM_DESCRIPTION" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.PROBLEM_DESCRIPTION.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."REQUESTER_PHONE" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.REQUESTER_PHONE.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."RESOLUTION_TEXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.RESOLUTION_TEXT.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."SEVERITY_TXT" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.SEVERITY_TXT.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."TICKET_ID" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.TICKET_ID.';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."TICKET_STATUS" IS 'TODO: define meaning, unit/format, null semantics, allowed values, source, and sensitivity for BAD_AI_READY.SUPPORT_TICKETS.TICKET_STATUS.';

-- Remediation: missing or stale optimizer statistics
-- Reason: LAST_ANALYZEDが未設定または古いため、Clean/Current score が低下します。
-- Purpose: Oracle optimizer統計を収集し、メタデータ上もデータ状態を確認しやすくします。
-- Review: 大きい表ではメンテナンス時間、DBMS_STATS設定、サンプリング方針をDBAと確認してください。
-- Target: BAD_AI_READY.EMPTY_EXPORT; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname => 'BAD_AI_READY',
    tabname => 'EMPTY_EXPORT',
    cascade => TRUE,
    method_opt => 'FOR ALL COLUMNS SIZE AUTO'
  );
END;
/

-- Template only: primary key candidates
-- Reason: 主キー未検出のため、Clean/Correlated/Consumable score が低下します。
-- Purpose: AI回答の根拠行を安定して参照できる業務キーを明確にします。
-- Review: 重複データ、NULL、既存アプリ影響、制約名、索引方針を確認するまで実行しないでください。
-- ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);
-- ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" ADD CONSTRAINT <constraint_name> PRIMARY KEY (<column_list>);

-- Template only: freshness column candidates
-- Reason: 鮮度列が未検出のため、Current score が低下し、AI回答でデータの新しさを説明しづらくなります。
-- Purpose: 更新日時、取込日時、有効期間などを明示し、RAG/agent回答の鮮度説明を可能にします。
-- Review: アプリが別の方法で鮮度を管理していないか確認し、列追加の影響をレビューしてください。
-- ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" ADD "UPDATED_AT" TIMESTAMP(6);
-- ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" ADD "UPDATED_AT" TIMESTAMP(6);

-- Review only: broad data grants
-- Reason: PUBLICなど広い相手へのデータアクセス権限があるため、Compliant score が低下します。
-- Purpose: AI利用前に公開範囲が意図通りかを確認し、不要な広い権限を減らします。
-- Review: REVOKEはアプリや利用者に影響するため、DBA/業務オーナー確認後に個別判断してください。
-- Review grant: SELECT on BAD_AI_READY.RAW_CUSTOMERS to PUBLIC
-- REVOKE SELECT ON "BAD_AI_READY"."RAW_CUSTOMERS" FROM "PUBLIC";
-- Review grant: SELECT on BAD_AI_READY.RAW_ORDERS to PUBLIC
-- REVOKE SELECT ON "BAD_AI_READY"."RAW_ORDERS" FROM "PUBLIC";
-- Review grant: SELECT on BAD_AI_READY.SUPPORT_TICKETS to PUBLIC
-- REVOKE SELECT ON "BAD_AI_READY"."SUPPORT_TICKETS" FROM "PUBLIC";

11. 手動レビューが必要な項目

  • 機微情報候補列: 10件。業務オーナーによる分類が必要です。
  • 広いデータ権限候補: 3件。DBA確認が必要です。
  • Semantic type mismatch候補: 11件。推定のため業務・アプリ仕様と照合してください。
  • 主キー、外部キー、更新日時、データ粒度、保持期間はアプリケーション仕様と照合してください。

12. 次のアクション

  1. 欠落しているテーブルコメント8件、カラムコメント52件を補完し、Mandatory comment gateをpassにします。
  2. 構造・運用メタデータを改善します: 主キー未定義8表、未取得または古い統計1表、鮮度列未定義8表、出所列未定義8表。
  3. 文字列型に保存された数値・日付候補11列を確認し、型付き列、仮想列、またはAI用Viewを検討します。
  4. DBA・業務オーナーがセキュリティとプライバシーを確認します: 広いデータ権限3件、機微情報候補10列。

改善前の主要指標を抜き出すと次のようになります。

指標 改善前 読み取り
Mandatory comment gate fail テーブル・カラムコメントがともに0%
Table comment coverage 0% テーブルの目的や粒度をAIへ説明できない
Column comment coverage 0% 単位、形式、コード値、機微性を説明できない
PK / Relationship coverage 0% 根拠行や表間関係をメタデータから判断できない
Freshness coverage 0% データの更新時点を説明できない
Source metadata coverage 0% データの出所を追跡できない
Sensitive documentation 0% 機微情報候補列が未説明
Broad data grant absence 62.5% 任意で付与したPUBLIC SELECTが検出された

特に重要なのがMandatory comment gateです。総合スコアが一定以上であっても、テーブルまたはカラムコメントが1件でも欠けると、本ポリシーでは未Readyとして扱われます。列名だけでは、AMOUNT_TXTがどの通貨の何を表すか、CHURN_SCORE_TXTは高いほど良いのか悪いのか、ORPHAN_REGIONSが何のマスタなのかをAIへ十分に伝えられないためです。

また、Skillが生成したSQLには、コメントのTODO、主キー候補、鮮度列候補、統計収集、PUBLIC権限のレビュー候補が含まれています。これはそのまま無条件に実行する完成SQLではなく、データモデルと業務ルールを確認するための出発点として利用します。

■ 改善SQLをレビューして実行

Skillが生成した改善SQLには、業務オーナーによるレビューを前提としたTODOコメントや、主キー・鮮度列の候補が出力されました。Skillがデータ・ディクショナリだけから業務上の正しい説明やキーを断定すると危険なため、候補として出力される設計になっています。

そこで、Skillが生成したbad_ai_ready_scan_before_improvement.sqlは元の候補として残し、RemediationReasonPurposeReviewの構成を維持したレビュー済みSQLをbad_ai_ready_scan_before_improvement_reviewed.sqlとして別ファイルに作成しました。今回のBAD_AI_READYスキーマに合わせて、次の内容を具体化しています。

改善カテゴリ 今回の対応
Contextual 8表と改善後68列へ、用途・粒度・形式・コード値・機微性をコメント
Clean 8件のPK、5件のFKをENABLE VALIDATEで追加し、統計情報を収集
Current 全8表へUPDATED_ATを追加
Correlated 全8表へSOURCE_SYSTEMを追加し、FKで関係を明示
Compliant 意図的に付与した3件のPUBLIC SELECTを削除

テストデータは一意性と参照整合性を満たしているため、行データの修復を挟まずにPK/FKを追加できます。以下のSQLは改善前スキーマに対して1回だけ実行する前提です。

レビュー済み改善SQLの内容はここをクリック
bad_ai_ready_scan_before_improvement_reviewed.sql
-- BAD_AI_READY Part 2: reviewed AI Ready remediation SQL.
--
-- oracle-ai-ready-data Skill が生成する改善SQLの形式に合わせ、
-- 条件分岐や動的SQLを使用せず、改善内容を1文ずつ明示しています。
--
-- Run as BAD_AI_READY after 02_load_csv.sql.
-- This script is intended to be run once against the pre-improvement schema.

set define off
set verify off
set feedback on
set timing on

whenever sqlerror exit sql.sqlcode rollback

-- Remediation: missing freshness and source metadata columns
-- Reason: 鮮度列と出所メタデータがないため、Current/Correlated score が低下します。
-- Purpose: 各行の最終更新日時と提供元システムを明示し、AI回答の鮮度説明と根拠追跡を可能にします。
-- Review: このSQLは改善前スキーマに対して1回実行します。既に列が存在する場合は実行しないでください。
ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" ADD ("SOURCE_SYSTEM" VARCHAR2(30));
ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" ADD ("UPDATED_AT" TIMESTAMP(6));
ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" ADD ("SOURCE_SYSTEM" VARCHAR2(30));

-- Remediation: populate freshness and source metadata values
-- Reason: 追加した列がNULLのままでは、データ鮮度と出所を行単位で説明できません。
-- Purpose: 既存データへ改善SQL実行時刻とデモ取込元を設定します。
-- Review: 実環境では実際の更新日時と提供元システムに置き換えてください。
UPDATE "BAD_AI_READY"."AI_DOCUMENTS" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."CUSTOMER_FEATURES" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."EMPTY_EXPORT" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."ORPHAN_REGIONS" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."RAW_CUSTOMERS" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."RAW_ORDERS" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."RAW_ORDER_LINES" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';
UPDATE "BAD_AI_READY"."SUPPORT_TICKETS" SET "UPDATED_AT" = SYSTIMESTAMP, "SOURCE_SYSTEM" = 'PART2_CSV';

-- Remediation: enforce freshness and source metadata defaults
-- Reason: 今後追加される行でも鮮度列と出所列が欠落しないようにします。
-- Purpose: UPDATED_ATとSOURCE_SYSTEMへDEFAULTおよびNOT NULL制約を設定します。
-- Review: アプリケーション側のINSERT仕様とデフォルト値への影響を確認してください。
ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);
ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" MODIFY ("UPDATED_AT" DEFAULT SYSTIMESTAMP NOT NULL);
ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" MODIFY ("SOURCE_SYSTEM" DEFAULT 'PART2_CSV' NOT NULL);

-- Remediation: missing primary keys
-- Reason: 主キー未検出のため、Clean/Correlated/Consumable score が低下します。
-- Purpose: AI回答の根拠行を安定して参照できる業務キーを明確にします。
-- Review: このデモデータはNULLと重複がないことを確認済みです。実環境では事前検証してください。
ALTER TABLE "BAD_AI_READY"."ORPHAN_REGIONS" ADD CONSTRAINT "PK_ORPHAN_REGIONS" PRIMARY KEY ("COUNTRY_CODE") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" ADD CONSTRAINT "PK_RAW_CUSTOMERS" PRIMARY KEY ("CUSTOMER_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" ADD CONSTRAINT "PK_RAW_ORDERS" PRIMARY KEY ("ORDER_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" ADD CONSTRAINT "PK_RAW_ORDER_LINES" PRIMARY KEY ("ORDER_ID", "LINE_NO") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."AI_DOCUMENTS" ADD CONSTRAINT "PK_AI_DOCUMENTS" PRIMARY KEY ("DOC_ID", "CHUNK_NUMBER") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" ADD CONSTRAINT "PK_CUSTOMER_FEATURES" PRIMARY KEY ("CUSTOMER_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" ADD CONSTRAINT "PK_SUPPORT_TICKETS" PRIMARY KEY ("TICKET_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."EMPTY_EXPORT" ADD CONSTRAINT "PK_EMPTY_EXPORT" PRIMARY KEY ("EXPORT_ID") ENABLE VALIDATE;

-- Remediation: missing foreign keys
-- Reason: 表間の関連が宣言されていないため、Contextual/Correlated score とJOINの説明可能性が低下します。
-- Purpose: 顧客、注文、明細、特徴量、問い合わせの参照関係を明示します。
-- Review: このデモデータは孤児行がないことを確認済みです。実環境では参照整合性を事前検証してください。
ALTER TABLE "BAD_AI_READY"."RAW_CUSTOMERS" ADD CONSTRAINT "FK_CUSTOMERS_REGION" FOREIGN KEY ("COUNTRY_CODE") REFERENCES "BAD_AI_READY"."ORPHAN_REGIONS" ("COUNTRY_CODE") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."RAW_ORDERS" ADD CONSTRAINT "FK_ORDERS_CUSTOMER" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "BAD_AI_READY"."RAW_CUSTOMERS" ("CUSTOMER_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."RAW_ORDER_LINES" ADD CONSTRAINT "FK_LINES_ORDER" FOREIGN KEY ("ORDER_ID") REFERENCES "BAD_AI_READY"."RAW_ORDERS" ("ORDER_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" ADD CONSTRAINT "FK_FEATURES_CUSTOMER" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "BAD_AI_READY"."RAW_CUSTOMERS" ("CUSTOMER_ID") ENABLE VALIDATE;
ALTER TABLE "BAD_AI_READY"."SUPPORT_TICKETS" ADD CONSTRAINT "FK_TICKETS_CUSTOMER" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "BAD_AI_READY"."RAW_CUSTOMERS" ("CUSTOMER_ID") ENABLE VALIDATE;

-- Remediation: missing table comments
-- Reason: テーブルコメントがないため、Contextual score と mandatory comment gate が低下します。
-- Purpose: テーブルの業務目的、粒度、更新頻度、機微性、AI利用時の注意点を明文化します。
-- Review: 以下は今回のデモ用にレビュー済みの説明です。実環境では業務オーナーの承認を得てください。
COMMENT ON TABLE "BAD_AI_READY"."AI_DOCUMENTS" IS '社内FAQや運用手順などの検索対象文書を1チャンク1行で保持する。粒度は文書チャンク、更新はデモCSV取込単位。AIはBODY_TEXTを検索対象とし、ORIGIN_URIを回答根拠の参照先として使用する。';
COMMENT ON TABLE "BAD_AI_READY"."CUSTOMER_FEATURES" IS '顧客分析用の特徴量を1顧客1行で保持する。粒度は顧客、更新はデモCSV取込単位。AIはセグメント説明や離反傾向の集計に使用し、個人を断定する用途には使用しない。';
COMMENT ON TABLE "BAD_AI_READY"."EMPTY_EXPORT" IS '外部出力ジョブの定義または結果を保持する予約表。粒度は1出力。デモでは空表であり、AIはデータが存在しないことを前提に扱う。';
COMMENT ON TABLE "BAD_AI_READY"."ORPHAN_REGIONS" IS '国コードと地域名、業務上のリスク区分を保持する参照マスタ。粒度は1国コード、更新はデモCSV取込単位。RAW_CUSTOMERSの国コード解釈に使用する。';
COMMENT ON TABLE "BAD_AI_READY"."RAW_CUSTOMERS" IS '顧客マスタのデモ取込データを1顧客1行で保持する。粒度は顧客、更新はデモCSV取込単位。連絡先や識別情報を含むため、AI回答では必要最小限の項目だけを使用する。';
COMMENT ON TABLE "BAD_AI_READY"."RAW_ORDERS" IS '注文ヘッダーを1注文1行で保持する。粒度は注文、更新はデモCSV取込単位。金額集計ではAMOUNT_TXTを数値へ変換し、通貨はCURRENCY_CODEと組み合わせて解釈する。';
COMMENT ON TABLE "BAD_AI_READY"."RAW_ORDER_LINES" IS '注文明細を1注文内の1明細1行で保持する。粒度は注文IDと明細番号の組合せ。数量、単価、割引率は文字列数値として保持するため、AI集計時は数値変換する。';
COMMENT ON TABLE "BAD_AI_READY"."SUPPORT_TICKETS" IS '顧客サポート問い合わせを1チケット1行で保持する。粒度はチケット、更新はデモCSV取込単位。本文に連絡先が含まれる可能性があるため、AI要約では個人情報を出力しない。';

-- Remediation: missing column comments
-- Reason: カラムコメントがないため、AIが列の意味、単位、形式、NULL、機微性を誤解する可能性があります。
-- Purpose: 各カラムの意味、形式、許容値、参照関係、機微性、AI利用時の注意を明文化します。
-- Review: 以下は今回のデモ用にレビュー済みの説明です。実環境では業務オーナーの承認を得てください。
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."DOC_ID" IS '原文書を識別する数値ID。CHUNK_NUMBERと組み合わせて文書チャンクを一意に識別する。NULL不可。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."ORIGIN_URI" IS '原文書の参照URI。回答根拠の追跡に使用する合成デモURI。NULL不可。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."TITLE_TXT" IS '原文書のタイトル。検索結果や回答根拠の表示名に使用する。NULL不可。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."BODY_TEXT" IS '検索、要約、回答生成の対象となる本文チャンク。NULL不可。合成デモ本文のみを保持する。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."CHUNK_NUMBER" IS '同一文書内のチャンク順序。1から始まる整数で、DOC_IDと組み合わせて主キーを構成する。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."EMBEDDING_BLOB_TXT" IS '旧取込形式との互換用に残した埋め込み文字列予約列。本デモではNULLであり、VECTOR型の代替として使用しない。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."LIFECYCLE_STATE" IS '文書チャンクの利用状態。許容値はREADYまたはARCHIVED。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."AI_DOCUMENTS"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."CUSTOMER_ID" IS '特徴量の対象顧客ID。RAW_CUSTOMERS.CUSTOMER_IDを参照し、1顧客1行を一意に識別する。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."CHURN_SCORE_TXT" IS '離反傾向スコアを0.00から0.99の小数文字列で保持する。高いほど離反傾向が高い。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."LIFETIME_VALUE_TXT" IS '顧客生涯価値の推定額を小数文字列で保持する。デモ上の基準通貨額で、集計時は数値変換する。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."SEGMENT_CODE" IS '顧客セグメントコード。許容値はS1、S2、S3、S4。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."FEATURE_NOTES" IS '特徴量の解釈に関する補足。NULLは補足事項なしを表す。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."CUSTOMER_FEATURES"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."EXPORT_ID" IS '外部出力を一意に識別する数値ID。表に行が追加された場合の主キー。';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."EXPORT_NAME" IS '外部出力の名称。NULLは名称未設定を表す。';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."PAYLOAD" IS '外部出力の内容または設定を保持するテキスト。NULLは内容未生成を表す。';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."EMPTY_EXPORT"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."COUNTRY_CODE" IS 'ISO 3166-1 alpha-2形式の国コード。RAW_CUSTOMERS.COUNTRY_CODEから参照される主キー。';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."REGION_NAME" IS '国コードに対応する地域または国の表示名。';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."RISK_TIER_TXT" IS '業務上のリスク区分。許容値はLOW、MEDIUM、HIGH。法的評価を表すものではない。';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."ORPHAN_REGIONS"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."CUSTOMER_ID" IS '顧客を一意に識別する数値ID。主キーであり、注文、特徴量、問い合わせから参照される。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."FULL_NAME" IS '顧客の表示名。合成データだが個人情報候補として扱い、AI出力では必要な場合だけ使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."EMAIL" IS '顧客のメールアドレス。合成データ。個人情報候補であり、AI回答への直接表示は原則避ける。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."PHONE" IS '顧客の電話番号。合成データ。個人情報候補であり、AI回答への直接表示は原則避ける。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."SSN" IS '社会保障番号相当の合成識別子。形式は999-99-9999。高機微情報候補であり、AI回答には表示しない。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."BIRTHDATE_TXT" IS '顧客の生年月日をYYYY-MM-DD形式の文字列で保持する。個人情報候補であり、年齢分析時だけ利用する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."COUNTRY_CODE" IS '顧客所在国のISO 3166-1 alpha-2コード。ORPHAN_REGIONS.COUNTRY_CODEを参照する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."SIGNUP_WHEN_TXT" IS '顧客登録日時をYYYY-MM-DD HH24:MI:SS形式の文字列で保持する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."STATUS_TXT" IS '顧客状態。許容値はACTIVE、INACTIVE、SUSPENDED。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."LAST_PURCHASE_AMT" IS '直近購入額を小数点以下2桁の数値文字列で保持する。集計時はTO_NUMBERで数値変換する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."NOTES" IS '顧客に関する補足メモ。合成データだが連絡先を含む可能性があるためAI出力前に確認する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_CUSTOMERS"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."ORDER_ID" IS '注文を一意に識別する文字列ID。主キーであり、RAW_ORDER_LINESから参照される。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."CUSTOMER_ID" IS '注文者の顧客ID。RAW_CUSTOMERS.CUSTOMER_IDを参照する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."ORDER_TIME_TXT" IS '注文日をYYYY-MM-DD形式の文字列で保持する。日付比較時はTO_DATEで変換する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."AMOUNT_TXT" IS '注文合計額を小数点以下2桁の数値文字列で保持する。通貨はCURRENCY_CODEで示し、集計時は数値変換する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."CURRENCY_CODE" IS '注文金額のISO 4217通貨コード。例はJPY、USD、GBP、EUR、SGD、AUD。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."SHIPPING_POSTAL_CODE" IS '配送先郵便番号。合成データ。所在地情報候補であり、AI回答への表示は必要最小限にする。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."PAYMENT_CARD_HINT" IS '決済カードの末尾4桁だけを示すマスク済み合成値。機微情報候補であり、AI回答には表示しない。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."ORDER_PAYLOAD" IS '注文チャネルなどの補助属性を保持するJSON形式テキスト。金額や顧客IDの正本としては使用しない。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDERS"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."ORDER_ID" IS '明細が属する注文ID。RAW_ORDERS.ORDER_IDを参照し、LINE_NOと組み合わせて主キーを構成する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."LINE_NO" IS '注文内の明細番号。1から始まる整数で、ORDER_IDとの組合せで一意。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."SKU" IS '販売商品のSKUコード。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."QUANTITY_TXT" IS '購入数量を正の整数文字列で保持する。集計時はTO_NUMBERで数値変換する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."UNIT_PRICE_TXT" IS '商品単価を小数点以下2桁の数値文字列で保持する。通貨は注文ヘッダーのCURRENCY_CODEに従う。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."DISCOUNT_TXT" IS '明細割引率を0から100の百分率数値文字列で保持する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."LINE_COMMENT" IS '明細の補足説明。NULLは補足なしを表す。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."RAW_ORDER_LINES"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."TICKET_ID" IS 'サポート問い合わせを一意に識別する文字列ID。主キー。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."CUSTOMER_ID" IS '問い合わせ元の顧客ID。RAW_CUSTOMERS.CUSTOMER_IDを参照する。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."SEVERITY_TXT" IS '問い合わせ重大度を1から5の整数文字列で保持する。5が最も重大。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."AGENT_EMAIL" IS '担当エージェントの社内メールアドレス。合成データ。個人情報候補として扱う。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."REQUESTER_PHONE" IS '問い合わせ元の電話番号。合成データ。個人情報候補であり、AI回答には表示しない。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."TICKET_STATUS" IS '問い合わせ状態。許容値はOPEN、IN_PROGRESS、RESOLVED、CLOSED。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."PROBLEM_DESCRIPTION" IS '問い合わせ内容の本文。連絡先などを含む可能性があるため、AI要約では個人情報を除外する。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."RESOLUTION_TEXT" IS '解決内容。未解決の場合はNULL。解決済み問い合わせではナレッジ候補として利用できる。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."UPDATED_AT" IS 'この行が最後に更新されたデータベース日時。AI回答でデータ鮮度を説明するために使用する。';
COMMENT ON COLUMN "BAD_AI_READY"."SUPPORT_TICKETS"."SOURCE_SYSTEM" IS 'この行を提供した元システム識別子。本デモではPART2_CSVを設定する。';

-- Remediation: broad data grants
-- Reason: PUBLICへの広いデータアクセス権限は、Compliant scoreとAI利用時の公開範囲に影響します。
-- Purpose: デモで意図的に付与したPUBLIC SELECTを削除します。
-- Review: 03_optional_public_grants.sqlを実行した場合だけ実行してください。依存利用者への影響を確認してください。
REVOKE SELECT ON "BAD_AI_READY"."RAW_CUSTOMERS" FROM PUBLIC;
REVOKE SELECT ON "BAD_AI_READY"."RAW_ORDERS" FROM PUBLIC;
REVOKE SELECT ON "BAD_AI_READY"."SUPPORT_TICKETS" FROM PUBLIC;

-- Remediation: missing or stale optimizer statistics
-- Reason: LAST_ANALYZEDが未設定または古いため、Clean/Current score が低下します。
-- Purpose: Oracle optimizer統計を収集し、メタデータ上もデータ状態を確認しやすくします。
-- Review: 大規模表ではメンテナンス時間、DBMS_STATS設定、サンプリング方針をDBAと確認してください。
-- Target: BAD_AI_READY.AI_DOCUMENTS; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'AI_DOCUMENTS',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.CUSTOMER_FEATURES; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'CUSTOMER_FEATURES',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.EMPTY_EXPORT; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'EMPTY_EXPORT',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.ORPHAN_REGIONS; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'ORPHAN_REGIONS',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.RAW_CUSTOMERS; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'RAW_CUSTOMERS',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.RAW_ORDERS; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'RAW_ORDERS',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.RAW_ORDER_LINES; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'RAW_ORDER_LINES',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/
-- Target: BAD_AI_READY.SUPPORT_TICKETS; stats_reason=missing
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
    ownname          => 'BAD_AI_READY',
    tabname          => 'SUPPORT_TICKETS',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
    cascade          => TRUE,
    method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
    no_invalidate    => FALSE
  );
END;
/

-- After execution, run 08_verify_after_improvement.sql and rerun the Skill scan profile.
-- Expected: Mandatory comment gate = pass.

1) ディレクトリ移動とファイル確認

cd oracle-ai-ready-data-main
ls -1 bad_ai_ready_scan_before_improvement*.sql
出力例
bad_ai_ready_scan_before_improvement.sql
bad_ai_ready_scan_before_improvement_reviewed.sql

2) 改善SQLを実行

レビュー済みのbad_ai_ready_scan_before_improvement_reviewed.sqlBAD_AI_READYで実行します。03_optional_public_grants.sqlを実行していない場合は、3件のREVOKEをコメントアウトするか、権限状況を確認してから実行します。

sql bad_ai_ready/<BAD_AI_READY_PASSWORD>@adb_high @bad_ai_ready_scan_before_improvement_reviewed.sql

3) 改善後のメタデータを検証

改善SQLの実行後は、Skillを再実行する前にパッケージの検証SQLで反映状況を確認します。

@08_verify_after_improvement.sql

主な期待値は次のとおりです。

確認項目 期待値
対象表 8
テーブルコメント 8
コメント設定済み列 68
有効・検証済みPK 8
有効・検証済みFK 5
UPDATED_ATを持つ表 8
SOURCE_SYSTEMを持つ表 8
統計取得済み表 8
PUBLIC SELECT / READ 0

この事前確認を入れることで、再評価でスコアが上がった理由を、実際に反映されたDDLと対応付けて説明できます。

■ Mermaid ER図で改善後のテーブル関係を確認

改善前のBAD_AI_READYスキーマには主キーと外部キーが設定されていなかったため、各テーブルはデータベースのメタデータ上では独立した状態でした。テーブル名やカラム名から人間が関係を推測できても、データベース側には顧客と注文、注文と注文明細といった参照関係が定義されていません。

改善SQLでは、全8表へ主キーを追加するとともに、顧客、注文、注文明細、顧客特徴量、問い合わせ、国コードマスタの関係を5本の外部キーとして定義しました。これにより、Relationship coverageConstraint coverageが改善し、Select AIへ表間の関係をメタデータとして渡せるようになります。

ということで、改善後のBAD_AI_READYスキーマをMermaidのER図で確認してみてみます。

● 改善後のMermaid ER図

すべてのカラムを表示すると図が複雑になるため、ここでは主キー、外部キー、および後半のSelect AI検証でJOINに利用する主要なカラムだけを表示します。

Mermaid ER図を確認すると、RAW_CUSTOMERSを中心に次の参照関係が定義されていることが分かります。

親テーブル 子テーブル 関連するカラム 外部キー
ORPHAN_REGIONS RAW_CUSTOMERS COUNTRY_CODE FK_CUSTOMERS_REGION
RAW_CUSTOMERS RAW_ORDERS CUSTOMER_ID FK_ORDERS_CUSTOMER
RAW_ORDERS RAW_ORDER_LINES ORDER_ID FK_LINES_ORDER
RAW_CUSTOMERS CUSTOMER_FEATURES CUSTOMER_ID FK_FEATURES_CUSTOMER
RAW_CUSTOMERS SUPPORT_TICKETS CUSTOMER_ID FK_TICKETS_CUSTOMER

特に、注文データの中心となる3表は次のようにつながっています。

RAW_CUSTOMERS
    |
    | CUSTOMER_ID
    v
RAW_ORDERS
    |
    | ORDER_ID
    v
RAW_ORDER_LINES

この関係を外部キーとして定義したことで、顧客から注文、注文から注文明細へたどるためのJOIN条件が明確になりました。後半のSelect AI検証では、AI Profileでconstraints=trueを有効にし、このPK/FK情報をSQL生成用のコンテキストへ含めます。

改善前後をER図の観点で整理すると、次のようになります。

状態 ER図で確認できる内容
改善前 PK/FKが未定義のため、テーブル間の関連線が表示されない
改善後 PK 8件とFK 5件が表示され、顧客・注文を中心とした関係を確認できる

AI_DOCUMENTSEMPTY_EXPORTは、今回のデータモデルではほかの表を参照しない独立した用途の表です。ER図上で外部キーの線がないこと自体は問題ではなく、それぞれに主キーが設定され、行を一意に識別できる状態になっていることを確認します。

なお、Mermaid ER図で可視化できるのは主にPK/FKなどの構造的な改善です。今回のAI Ready改善には、テーブル・カラムコメント、統計情報、UPDATED_ATSOURCE_SYSTEM、機微情報候補の説明、PUBLIC権限の削除も含まれています。これらを含めた最終的な改善結果は、続けてoracle-ai-ready-data Skillを再実行して確認します。

■ 改善後にSkillを再実行

改善前と同じscan Profileでメタデータを再収集します。Profileや対象表を変えずに再評価することで、改善SQLによる変化を比較できます。Before/Afterのファイルを上書きしないよう、改善後の出力名にはafterを付けます。

1) ディレクトリ移動

cd oracle-ai-ready-data-main

2) 改善後メタデータを収集
メタデータ .outファイルが出力されます。

今回の環境用に 引数は次を使用します。

 schema: admin
 schema_owner:  BAD_AI_READY
oracle-ai-ready-data実行
sql -s <schema>/<ADMIN_PASSWORD>@adb_high \
  @scripts/oracle_ai_ready_collect.sql <schema_owner> % scan

3) メタデータ .outファイル確認
このファイルを使用してレポート整形することができます。
レポートファイル名は、oracle-ai-ready-data 実行した引数を利用して生成されます。

.outファイル確認
# ls -ltr
・・・
    -rw-r--r--  1 shirok  staff  29441 Jul 21 14:50 oracle_ai_ready_scan_BAD_AI_READY_scan.out

4) 改善後レポートを生成

レポートとチューニングSQL生成
python3 scripts/score_oracle_ai_ready_scan.py \
  oracle_ai_ready_scan_BAD_AI_READY_scan.out \
  --profile scan \
  --language ja \
  --output bad_ai_ready_scan_after_report.md \
  --html-output bad_ai_ready_scan_after_report.html \
  --sql-output bad_ai_ready_scan_after_improvement.sql

5) 改善後の生成ファイルを確認
改善後レポートと、追加で必要な改善SQLが生成されていることを確認します。今回のメタデータで自動生成対象が残っていなければ、SQL側にはNo executable improvement SQL generatedと出力されます。

.md マークダウンファイル: AI Ready評価レポート
.html HTMLファイル: 人が確認しやすいAI Ready評価レポート
.sqlファイル: AI Ready改善SQL候補
レポートとチューニングSQL生成確認
$ ls -ltr
・・・
    -rw-r--r--  1 shirok  staff  29441 Jul 21 14:50 oracle_ai_ready_scan_BAD_AI_READY_scan.out
    -rw-r--r--  1 shirok  staff  12452 Jul 21 14:51 bad_ai_ready_scan_after_report.md
    -rw-r--r--  1 shirok  staff  10234 Jul 21 14:51 bad_ai_ready_scan_after_report.html
    -rw-r--r--  1 shirok  staff     72 Jul 21 14:51 bad_ai_ready_scan_after_improvement.sql

■ 改善後のOracle Database AI Ready評価

改善後のレポートでは、総合スコアが0.97となり、Mandatory comment gateとComment quality reviewがともにpassしました。結論もAI Ready候補へ変わっています。評価対象列が52列から68列へ増えているため、追加したUPDATED_ATSOURCE_SYSTEMも正しく評価対象に含まれています。一方、Semantic type mismatch候補11件は残っており、メタデータ整備後も型設計のレビューが必要であることが分かります。

bad_ai_ready_scan_after_report.md 内容(確認はここをクリック)

Oracle Database AI Ready 評価レポート

1. エグゼクティブサマリー

  • 総合スコア: 0.97 / 1.00
  • Profile: scan
  • Mandatory comment gate: pass
  • Comment quality review: pass
  • Semantic type warnings: 11件
  • 結論: AI Ready候補
  • コメント有無チェックは必須条件です。コメント品質とSemantic type mismatchは初期実装では警告であり、既存スコアには影響しません。

2. スコープと前提

項目
Schema BAD_AI_READY
Table pattern %
Profile scan
評価対象テーブル数 8
評価対象カラム数 68
SQLcl spool oracle_ai_ready_scan_BAD_AI_READY_scan.out
Scan timestamp 2026-07-21T05:50:04.843069 +00:00
注意事項 ALL_* dictionary viewsで見えるメタデータを評価します。実データ値、業務上の正しさ、法令遵守は別途レビューが必要です。

3. 評価項目の説明

Dimension Weight 何を評価しているか なぜ重要か
Clean 20.0% 主キー、制約、統計情報があり、AI処理の前提となる構造的な信頼性を確認します。 キーや統計情報が不足すると、根拠行の特定、結合、品質確認が不安定になります。
Contextual 25.0% テーブル/カラムコメントとリレーション定義により、データの意味が説明できるかを確認します。 AIが列名だけから意味を推測すると誤解しやすいため、コメントを必須ゲートにしています。
Consumable 15.0% AIやRAGパイプラインが利用しやすいテキスト列、VECTOR列、安定ID、ドキュメントを確認します。 検索対象、根拠、embedding管理方法が曖昧だと、RAG/agentの回答品質が安定しません。
Current 15.0% 更新日時などの鮮度列と最近の統計情報があり、データの新しさを説明できるかを確認します。 古いデータや更新時点不明のデータは、AI回答の鮮度リスクになります。
Correlated 15.0% 外部キー、主キー、source/update系メタデータにより、他テーブルや元データと関連付けられるかを確認します。 関連が宣言されていないと、AIが表間のつながりを誤解したり、根拠追跡が弱くなります。
Compliant 10.0% 機微情報らしい列名、コメント有無、広い権限付与候補を検出し、レビュー可能性を確認します。 この評価は法令遵守を保証しませんが、AI利用前のセキュリティ/プライバシーレビュー対象を明確にします。

4. スコアカード

Dimension Weight Score 主な根拠
Clean 20.0% 1.00 PK 100.0%, table stats 100.0%, column stats 100.0%, constraints 100.0%
Contextual 25.0% 1.00 table comments 100.0%, column comments 100.0%, relationships 100.0%
Consumable 15.0% 1.00 text-bearing tables 100.0%, vector tables 0.0%, documentation 100.0%, PK 100.0%
Current 15.0% 1.00 freshness columns 100.0%, recent stats 100.0%
Correlated 15.0% 0.83 FK 62.5%, source metadata 100.0%, PK 100.0%
Compliant 10.0% 0.96 sensitive documented 100.0%, broad data grant absence 100.0%

5. メトリクス詳細

Metric Value Status 説明
Table comment coverage 100.0% pass コメントが設定されている評価対象テーブルの割合です。100%でない場合は必須ゲートがfailです。
Column comment coverage 100.0% pass コメントが設定されている評価対象カラムの割合です。100%でない場合は必須ゲートがfailです。
PK coverage 100.0% 良好 有効な主キーがあるテーブルの割合です。AI回答の根拠行を安定して参照するために重要です。
FK coverage 62.5% 要確認 外部キーを持つ、または外部キー関係に参加するテーブルの割合です。表間の関連を安全に扱うための指標です。
Relationship coverage 100.0% 良好 主キーまたは外部キーのいずれかを持つテーブルの割合です。データモデルの説明可能性を見ます。
Constraint coverage 100.0% 良好 主キー、一意、外部キー、CHECK制約のいずれかがあるテーブルの割合です。構造的な品質管理の指標です。
Table stats coverage 100.0% 良好 LAST_ANALYZEDが入っているテーブルの割合です。統計情報が未取得だとデータ状態の確認が弱くなります。
Column stats coverage 100.0% 良好 LAST_ANALYZEDが入っているカラムの割合です。列分布やNULL傾向の評価に使います。
Recent stats coverage 100.0% 良好 統計情報が最近取得されているテーブルの割合です。既定では90日以内をrecentと見なします。
Freshness coverage 100.0% 良好 UPDATED_ATやLAST_UPDATE_DATEなど、鮮度を示す列があるテーブルの割合です。
Source metadata coverage 100.0% 良好 SOURCE_SYSTEM、BATCH_ID、CREATED_BYなど、出所や更新者を示す列があるテーブルの割合です。
Text-bearing table coverage 100.0% 参考 RAG候補となるテキスト列を持つテーブルの割合です。検索対象テキストの有無を確認します。
Vector table coverage 0.0% 参考 VECTOR型またはembedding候補を持つテーブルの割合です。embeddingを外部管理している場合は設計書で補足してください。
Sensitive candidate documentation 100.0% 良好 機微情報候補列のうちコメントがある列の割合です。列名ベース推定なので人間の分類が必要です。
Broad data grant absence 100.0% 良好 PUBLICなど広い相手へのデータアクセス権限が検出されなかった割合です。高いほどリスクが低い見立てです。
Table comment quality coverage 100.0% pass コメント本文がplaceholder、短すぎる説明、汎用文ではない割合です。初期実装では警告のみです。
Column comment quality coverage 100.0% pass コメント本文がplaceholder、短すぎる説明、汎用文ではない割合です。初期実装では警告のみです。

6. Mandatory comment gate

Check Coverage Result Required action
Table comments 100.0% pass Missing 0 table comments
Column comments 100.0% pass Missing 0 column comments

7. 主要な発見事項

High priority

  • High priority の自動検出事項はありません。

Medium priority

  • 機微情報候補列が 10 件あります。列名ベースの推定のため、業務オーナーによる分類が必要です。

Low priority / manual review

  • VECTOR型カラムは未検出です。embeddingを別スキーマや外部サービスで管理している場合は設計書に明記してください。

8. コメント品質

項目
Table comment quality coverage 100.0%
Column comment quality coverage 100.0%
Placeholder comments 0
Too-short comments 0
Generic/name-only comments 0
Repeated generic groups 0
  • コメント品質の自動レビュー対象はありません。

9. Semantic type mismatch

文字列型ですが、列名またはコメントから数値・日付として扱われる可能性がある列です。推定結果のため、自動的な型変更は行いません。

Column DB type 推定される意味 根拠 推奨対応
BAD_AI_READY.CUSTOMER_FEATURES.CHURN_SCORE_TXT VARCHAR2 NUMBER name: SCORE; comment: 小数文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.CUSTOMER_FEATURES.LIFETIME_VALUE_TXT VARCHAR2 NUMBER name: VALUE; comment: 小数文字列, 数値変換 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_CUSTOMERS.BIRTHDATE_TXT VARCHAR2 DATE/TIMESTAMP name: BIRTHDATE; comment: yyyy-mm-dd DATE/TIMESTAMP列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_CUSTOMERS.LAST_PURCHASE_AMT VARCHAR2 NUMBER name: AMT; comment: to_number, 数値変換, 数値文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_CUSTOMERS.SIGNUP_WHEN_TXT VARCHAR2 DATE/TIMESTAMP name: WHEN; comment: hh24:mi:ss, yyyy-mm-dd, 日時を DATE/TIMESTAMP列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDERS.AMOUNT_TXT VARCHAR2 NUMBER name: AMOUNT; comment: 数値変換, 数値文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDERS.ORDER_TIME_TXT VARCHAR2 DATE/TIMESTAMP name: TIME; comment: to_date, yyyy-mm-dd DATE/TIMESTAMP列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDER_LINES.DISCOUNT_TXT VARCHAR2 NUMBER name: DISCOUNT; comment: 数値文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDER_LINES.QUANTITY_TXT VARCHAR2 NUMBER name: QUANTITY; comment: to_number, 数値変換, 整数文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.RAW_ORDER_LINES.UNIT_PRICE_TXT VARCHAR2 NUMBER name: PRICE; comment: 数値文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。
BAD_AI_READY.SUPPORT_TICKETS.SEVERITY_TXT VARCHAR2 NUMBER name: SEVERITY; comment: 整数文字列 NUMBER列、仮想列、または型付きAI用Viewを検討してください。

10. 改善SQLの考え方

SQLカテゴリ 理由 目的 実行前確認
COMMENT ON TABLE / COLUMN コメント欠落はmandatory gateとContextual scoreを下げます。 業務意味、粒度、単位、NULL意味、機微性を明文化します。 TODO文を実説明に置換し、業務オーナー承認後に実行します。
Comment quality review コメントが存在してもplaceholderや汎用文ではAIへ十分な意味を伝えられません。 実際の業務説明へ置き換えます。 自動上書きはせず、人間がレビューします。
Semantic type review 文字列型に数値・日付が保存されるとNL2SQLで暗黙変換や文字列比較が発生します。 型付き列、仮想列、AI用Viewを検討します。 自動ALTERは生成しません。データとアプリ影響を確認します。
DBMS_STATS.GATHER_TABLE_STATS LAST_ANALYZED未設定/古い統計はClean/Current scoreを下げます。 統計情報を収集します。 大規模表ではDBA確認が必要です。
PRIMARY KEY / freshness column キーや鮮度列の不足は根拠追跡や新しさ説明を弱くします。 根拠行の特定と鮮度説明を可能にします。 テンプレートのため設計レビューが必要です。
REVOKE候補 広いデータ権限はAI利用前の公開範囲確認が必要です。 不要な公開を減らします。 依存利用者への影響を確認します。
-- No executable improvement SQL generated from the available metadata.

11. 手動レビューが必要な項目

  • 機微情報候補列: 10件。業務オーナーによる分類が必要です。
  • 広いデータ権限候補: 0件。DBA確認が必要です。
  • Semantic type mismatch候補: 11件。推定のため業務・アプリ仕様と照合してください。
  • 主キー、外部キー、更新日時、データ粒度、保持期間はアプリケーション仕様と照合してください。

12. 次のアクション

  1. 文字列型に保存された数値・日付候補11列を確認し、型付き列、仮想列、またはAI用Viewを検討します。
  2. DBA・業務オーナーがセキュリティとプライバシーを確認します: 機微情報候補10列。

改善前後を並べると、改善SQLの効果が分かりやすくなります。

指標 改善前 改善後
総合スコア 0.22 0.97
Mandatory comment gate fail pass
Table comment coverage 0% 100%
Column comment coverage 0% 100%
PK coverage 0% 100%
Relationship coverage 0% 100%
Constraint coverage 0% 100%
Table / Column stats 一部または未取得 100%
Freshness coverage 0% 100%
Source metadata coverage 0% 100%
Sensitive documentation 0% 100%
Broad data grant absence 62.5% 100%
Comment quality review fail pass
Semantic type warnings 11件 11件(手動レビュー継続)

CleanContextualConsumableCurrentは1.00となり、コメント、キー、統計、鮮度、出所の整備が評価へ反映されています。Correlatedが0.83なのは、8表のうちFKを所有する表が5表であることによるもので、独立したAI_DOCUMENTSEMPTY_EXPORTへスコア目的の不自然なFKを追加する必要はありません。Relationship coverageConstraint coverageは100%であり、今回のモデルに必要な関係は定義できています。

また、コメント品質は100%へ改善しましたが、文字列型に数値や日付を保存しているSemantic type mismatch候補は11件残りました。これは後半のSelect AIで確認した暗黙変換や文字列比較と対応しており、必要に応じてNUMBER/DATE列、仮想列、または型付きAI用Viewを検討する余地があります。

機微情報候補列は10件残っていますが、コメント設定率は100%です。これは「機微情報が存在しなくなった」という意味ではなく、利用前に人間が分類・権限・マスキング方針を確認できる状態になったことを表します。

また、改善後SQLには次の内容が出力されています。

-- No executable improvement SQL generated from the available metadata.

少なくともSkillが自動生成対象としているコメント欠落や統計不足について、追加の改善候補がないことを確認できました。

改善後の「次のアクション」は未解決項目から動的に生成されます。今回の場合、解決済みのコメント、PK/FK、統計、鮮度、出所は再度表示されず、Semantic type mismatch候補11件と機微情報候補10件のレビューだけが残りました。

ここまででメタデータ上のAI Ready改善は確認できました。続いて、整備したコメントとPK/FKが、自然言語からSQLを生成するSelect AIで実際に利用できるかを確認します。

■ Select AIでAI Ready Dataを機能確認

Skillの再評価は、コメントや制約などのメタデータが整備されたことを確認する評価です。ここでは一歩進めて、そのメタデータがSelect AIのNL2SQL生成で実際に利用できるかを確認します。

AI Profileは、パッケージの11_create_select_ai_profile.sqlで対象8表を限定し、comments=trueconstraints=trueを有効にしています。これにより、表・列コメントとPK/FKなどの制約情報をSQL生成用のコンテキストへ含めます。

Select AIの基本設定は次の記事の手順を使用します。

Select AIの基本設定と実行例

AI Ready Dataへ改善した後のスキーマでは、多くの問い合わせで適切な対象表、JOIN条件、集計条件を含むSQLが生成され、参照SQLと同じ結果を確認できました。一方で、条件漏れや暗黙的な型変換も確認できたため、SHOWSQLによるレビューを前提に評価します。

Test 01〜Test 10のベースラインはgpt-3.5-turboで実行しました。Test 08で業務条件の欠落が見つかったため、メタデータ、AI Profileの対象表、自然言語プロンプトは変更せず、LLMだけをgpt-5.4-nanoへ変更して再実行しています。本記事の主目的はモデルのベンチマークではなく、同じAI Ready DataでもLLMによって生成SQLが変わることの確認です。比較したのはTest 08のみであり、1問の結果だけでモデル全体の優劣を判断するものではありません。

● AI Profileを現在のセッションへ設定

AI Profileはセッション単位で有効になるため、SQLclへ接続するたびにDBMS_CLOUD_AI.SET_PROFILEを実行します。以降は、原則としてSHOWSQLで生成SQLを確認してからRUNSQLで結果を取得します。

AI Profileを設定
EXEC DBMS_CLOUD_AI.SET_PROFILE('BAD_AI_READY_OPENAI');
出力結果
SQL> EXEC DBMS_CLOUD_AI.SET_PROFILE('BAD_AI_READY_OPENAI');

    PL/SQL procedure successfully completed.

● Select AIテストの正誤判定方法

Select AIの出力は、SQLや結果がもっともらしく見えるだけでは正しいと判定できません。そこで本検証では、パッケージに含まれる14_select_ai_reference_sql.sql正解を作るための参照SQLとして先に実行し、その結果を各Testの想定回答としました。

参照SQLを実行
@14_select_ai_reference_sql.sql

正誤判定では、生成SQLの文字列が参照SQLと完全に同じかではなく、次を確認します。

  1. 適切な表を選択していること
  2. PK/FKと同じカラムでJOINしていること
  3. 自然言語で指定した絞込み条件がすべて入っていること
  4. 数値・日付文字列を必要に応じて明示的に型変換していること
  5. 機微情報を不要に出力していないこと
  6. RUNSQLの行数、値、並び順が参照SQLの想定回答と一致すること

判定は次の3段階とします。

判定 意味
PASS 想定回答と一致し、生成SQLにも重要な問題がない
条件付きPASS 想定回答とは一致したが、暗黙変換や文字列比較などSQL品質上の注意がある
FAIL 必須条件が欠落し、想定回答と実行結果が一致しない

● Select AIテスト結果マトリクス

まず、gpt-3.5-turboで実行したTest 01〜Test 10を、参照SQLの想定回答と比較します。10件中9件は想定回答と一致しましたが、そのうち2件には型変換上の注意があり、Test 08は条件漏れにより結果が不一致となりました。

・ gpt-3.5-turboによるベースライン

Test 主な確認内容 想定回答の要点 判定 理由
Test 01 基本的な表選択 顧客数50 PASS RAW_CUSTOMERSを選択し、50件を返した
Test 02 国マスタとのJOIN 6か国、件数7,7,7,7,6,6 PASS COUNTRY_CODEで正しくJOINし、ACTIVEも反映した
Test 03 顧客・注文JOIN、金額集計 日本のACTIVE顧客6件、先頭は顧客31・141.95 JPY 条件付きPASS 結果は一致したが、VARCHAR2の金額をSUMで暗黙変換した
Test 04 日付・金額の型変換 2025-01〜2025-10、6通貨ずつ合計60行 PASS TO_DATETO_NUMBERを明示し、60行すべて一致した
Test 05 未注文顧客のアンチJOIN 0 PASS 顧客と注文をCUSTOMER_IDで関連付け、0人を返した
Test 06 問い合わせ・顧客JOIN 顧客ID3,10,13,20,25,35,48、各1件 PASS 状態、重大度、JOIN、個人情報抑制を反映した
Test 07 特徴量の意味と数値集計 S1=2/3503.25S2=5/2697.5S3=3/1598.75 条件付きPASS 結果は一致したが、離反スコアを文字列比較した
Test 08-A 3表JOINと有効顧客条件 指定10 SKU、各数量2 FAIL STATUS_TXT='ACTIVE'が欠落し、別のSKUが結果へ混入した
Test 09 鮮度・出所メタデータ PART2_CSV、100行、最大UPDATED_AT PASS 改善SQLで追加した2列を正しく使用した
Test 10 コメントによる空表選択 0 PASS 業務用語からEMPTY_EXPORTを正しく選択した
PASS             : 7件
条件付きPASS     : 2件
FAIL             : 1件
想定回答との一致 : 9 / 10件

・ Test 08だけLLMを変更して再テスト

Test 08-AのFAILを受け、同じスキーマ、同じコメント、同じPK/FK、同じ対象表、同じ日本語プロンプトのまま、LLMだけを変更しました。

Test LLM プロンプト 回答結果 SHOWSQL 総合判定
Test 08-A gpt-3.5-turbo 同一 想定回答と不一致 ACTIVE条件が欠落 FAIL
Test 08-B gpt-5.4-nano 同一 想定回答と一致 3表JOIN、ACTIVEJPTO_NUMBERを確認 PASS

Test 08-Bは1問に対する再テスト結果です。gpt-5.4-nanoがすべての問い合わせで常に正しいことを意味しません。モデル全体を比較する場合は、Test 01〜Test 10を同じ条件で再実行し、正解率を比較する必要があります。

● Test 01 — 基本的な表選択

最初に、業務用語の「顧客」からRAW_CUSTOMERSを選択できるかを確認します。単一表の件数取得なので、Profileとオブジェクト選択が機能していることを確認する最小のテストです。

問い合わせ内容
SELECT AI 顧客は全部で何人ですか?;

想定回答

50

参照SQLと同じく、RAW_CUSTOMERSの全50行を数えられればPASSです。

出力結果
SQL> SELECT AI RUNSQL 顧客は全部で何人ですか?;

       TOTAL_CUSTOMERS
    __________________
                    50
    
    1 row selected.


SQL> SELECT AI SHOWSQL 顧客は全部で何人ですか?;

    RESPONSE
    ___________________________________________________
    SELECT COUNT("CUSTOMER_ID") AS "TOTAL_CUSTOMERS"
    FROM "BAD_AI_READY"."RAW_CUSTOMERS"
    
    1 row selected.

● Test 02 — コメントと国マスタの関係

次は、物理名がORPHAN_REGIONSである表を国コード参照マスタとして理解し、RAW_CUSTOMERS.COUNTRY_CODEと結合できるかを確認します。表コメントとFKの両方が効きやすいケースです。

問い合わせ内容
SELECT AI 有効な顧客数を国名別に集計し、人数の多い順、同数の場合は国名の昇順で表示してください。;

想定回答

国名 有効顧客数
Australia 7
Germany 7
Singapore 7
United States 7
Japan 6
United Kingdom 6

6行の値と並び順が一致し、STATUS_TXT='ACTIVE'が生成SQLへ含まれていればPASSです。

出力結果
SQL> SELECT AI 有効な顧客数を国名別に集計し、人数の多い順、同数の場合は国名の昇順で表示してください。;

    COUNTRY_NAME         VALID_CUSTOMER_COUNT
    _________________ _______________________
    Australia                               7
    Germany                                 7
    Singapore                               7
    United States                           7
    Japan                                   6
    United Kingdom                          6
    
    6 rows selected.

SQL> SELECT AI SHOWSQL 有効な顧客数を国名別に集計し、人数の多い順、同数の場合は国名の昇順で表示してください。;

    RESPONSE
    __________________________________________________________________________________________________________________
    SELECT ORPHAN_REGIONS.REGION_NAME AS "Country Name", COUNT(RAW_CUSTOMERS.CUSTOMER_ID) AS "Valid Customer Count"
    FROM BAD_AI_READY.RAW_CUSTOMERS
    JOIN BAD_AI_READY.ORPHAN_REGIONS ON RAW_CUSTOMERS.COUNTRY_CODE = ORPHAN_REGIONS.COUNTRY_CODE
    WHERE RAW_CUSTOMERS.STATUS_TXT = 'ACTIVE'
    GROUP BY ORPHAN_REGIONS.REGION_NAME
    ORDER BY COUNT(RAW_CUSTOMERS.CUSTOMER_ID) DESC, ORPHAN_REGIONS.REGION_NAME ASC
    
    1 row selected.

● Test 03 — 顧客・注文JOIN、文字列金額、個人情報抑制

顧客と注文をCUSTOMER_IDで結合し、日本のACTIVE顧客だけを対象に、通貨を混在させずに注文金額を集計します。さらに、メールアドレス、電話番号、SSN、カード情報を出力しないよう明示し、機微情報候補の扱いも確認します。

問い合わせ内容
SELECT AI 日本の有効な顧客について、顧客ID、顧客名、注文金額合計、通貨コードを表示し、注文金額合計の大きい順、同額の場合は顧客IDの昇順で上位10件を表示してください。異なる通貨は合算せず、メールアドレス、電話番号、SSN、カード情報は表示しないでください。;

想定回答

顧客ID 顧客名 注文金額合計 通貨コード
31 Demo Customer 031 141.95 JPY
43 Demo Customer 043 127 JPY
25 Demo Customer 025 117.55 JPY
37 Demo Customer 037 102.6 JPY
19 Demo Customer 019 93.15 JPY
1 Demo Customer 001 83.7 JPY

6行の値と並び順が一致し、個人情報候補列が出力されなければ回答結果はPASSです。加えて、金額を数値として安全に集計しているかをSHOWSQLで確認します。

出力結果
SQL> SELECT AI 日本の有効な顧客について、顧客ID、顧客名、注文金額合計、通貨コードを表示し、注文金額合計の大きい順、同額の場合は顧客IDの昇順で上位10件を表示してください。異なる通貨は合算せず、メールアドレス、電話番号、SSN、カード情報は表示しないでください。;

       顧客ID 顧客名                     注文金額合計 通貨コード
    _______ ____________________ _________ ________
         31 Demo Customer 031       141.95 JPY
         43 Demo Customer 043          127 JPY
         25 Demo Customer 025       117.55 JPY
         37 Demo Customer 037        102.6 JPY
         19 Demo Customer 019        93.15 JPY
          1 Demo Customer 001         83.7 JPY
    
    6 rows selected.

SQL> SELECT AI SHOWSQL 日本の有効な顧客について、顧客ID、顧客名、注文金額合計、通貨コードを表示し、注文金額合計の大きい順、同額の場合は顧客IDの昇順で上位10件を表示してください。異なる通貨は合算せず、メールアドレス、電話番号、SSN、カード情報は表示しないでください。;

    RESPONSE
    ____________________________________________________________________________
    SELECT
        RC."CUSTOMER_ID" AS "顧客ID",
        RC."FULL_NAME" AS "顧客名",
        SUM(RO."AMOUNT_TXT") AS "注文金額合計",
        RO."CURRENCY_CODE" AS "通貨コード"
    FROM
        "BAD_AI_READY"."RAW_CUSTOMERS" RC
    JOIN
        "BAD_AI_READY"."RAW_ORDERS" RO ON RC."CUSTOMER_ID" = RO."CUSTOMER_ID"
    WHERE
        RC."COUNTRY_CODE" = 'JP'
        AND RC."STATUS_TXT" = 'ACTIVE'
    GROUP BY
        RC."CUSTOMER_ID",
        RC."FULL_NAME",
        RO."CURRENCY_CODE"
    ORDER BY
        SUM(RO."AMOUNT_TXT") DESC,
        RC."CUSTOMER_ID" ASC
    FETCH FIRST 10 ROWS ONLY
    
    1 row selected.

Test 03の判定:条件付きPASS
RUNSQLの6行は想定回答と一致し、JOIN、JPACTIVE、通貨別集計、個人情報を出力しない条件も反映されました。一方、生成SQLはSUM(RO."AMOUNT_TXT")となり、VARCHAR2の金額をOracle Databaseの暗黙変換に任せています。

なぜ注意が必要か
今回は全データが小数点形式の数値文字列だったため正しく計算されました。しかし、不正値が混ざるとORA-01722: invalid numberになる可能性があり、セッションのNLS_NUMERIC_CHARACTERSによって小数点の解釈が変わる可能性もあります。結果が合っていても、再現性と安全性の面では明示変換が望まれます。

対応策

  1. 自然言語に「注文金額は数値として変換して集計してください」と明記する
  2. SHOWSQLTO_NUMBER(AMOUNT_TXT)が含まれることを確認する
  3. 実運用ではNUMBER列、型付き仮想列、またはAI向けViewを用意する

修正プロンプト例です。

SELECT AI SHOWSQL
日本の有効な顧客について、顧客ID、顧客名、注文金額合計、通貨コードを表示してください。
注文金額は数値として変換して集計し、異なる通貨は合算しないでください。
注文金額合計の大きい順、同額の場合は顧客IDの昇順で上位10件を表示してください。
メールアドレス、電話番号、SSN、カード情報は表示しないでください。;

参照SQLでは、NLS設定の影響も抑えるため次のように明示変換しています。

SUM(
  TO_NUMBER(
    RO.AMOUNT_TXT,
    '999999999999D99',
    q'[NLS_NUMERIC_CHARACTERS='.,']'
  )
)

● Test 04 — 文字列日付と文字列金額

ORDER_TIME_TXTAMOUNT_TXTは文字列列です。カラムコメントに記載した形式をもとに、日付と数値へ変換して月別・通貨別に集計できるかを確認します。

問い合わせ内容
SELECT AI 2025年の注文金額を月別、通貨別に集計し、
月の昇順、通貨コードの昇順で表示してください。
異なる通貨は合算しないでください。;

想定回答

  • 2025年1月から10月までの10か月
  • 各月にAUDEURGBPJPYSGDUSDの6通貨
  • 合計60行
  • 先頭行は2025-01 / AUD / 31.38
  • 最終行は2025-10 / USD / 126.58

14_select_ai_reference_sql.sqlの60行と、月・通貨・合計金額・並び順がすべて一致すればPASSです。

出力結果
SQL> SELECT AI 2025年の注文金額を月別、通貨別に集計し、月の昇順、通貨コードの昇順で表示してください。異なる通貨は合算しないでください。;

    ORDER_MONTH    CURRENCY_CODE       TOTAL_AMOUNT
    ______________ ________________ _______________
    2025-01        AUD                        31.38
    2025-01        EUR                        109.6
    2025-01        GBP                         91.8
    2025-01        JPY                        113.2
    2025-01        SGD                        79.25
    2025-01        USD                        130.7
    2025-02        AUD                        59.23
    2025-02        EUR                        73.05
    2025-02        GBP                        53.35
    2025-02        JPY                        134.5
    2025-02        SGD                       154.65
    2025-02        USD                        98.85
    2025-03        AUD                        28.17
    2025-03        EUR                       106.12
    2025-03        GBP                          100
    2025-03        JPY                         64.7
    2025-03        SGD                        184.7
    2025-03        USD                       141.99
    2025-04        AUD                        64.93
    2025-04        EUR                        32.45
    2025-04        GBP                        91.65
    2025-04        JPY                        145.2
    2025-04        SGD                        58.55
    2025-04        USD                       167.89
    2025-05        AUD                        74.65
    2025-05        EUR                        114.6
    2025-05        GBP                        42.65
    2025-05        JPY                        166.5
    2025-05        SGD                        197.9
    2025-05        USD                       186.53
    2025-06        AUD                        60.46
    2025-06        EUR                        64.16
    2025-06        GBP                        164.2
    2025-06        JPY                         78.6
    2025-06        SGD                           49
    2025-06        USD                        92.12
    2025-07        AUD                          135
    2025-07        EUR                         37.5
    2025-07        GBP                        122.5
    2025-07        JPY                        91.15
    2025-07        SGD                        156.3
    2025-07        USD                       110.02
    2025-08        AUD                        160.9
    2025-08        EUR                        60.13
    2025-08        GBP                        156.5
    2025-08        JPY                        52.85
    2025-08        SGD                        135.1
    2025-08        USD                         58.8
    2025-09        AUD                         55.8
    2025-09        EUR                        69.84
    2025-09        GBP                       186.55
    2025-09        JPY                        99.35
    2025-09        SGD                         54.2
    2025-09        USD                       108.67
    2025-10        AUD                       172.19
    2025-10        EUR                        38.05
    2025-10        GBP                        101.8
    2025-10        JPY                           91
    2025-10        SGD                        145.8
    2025-10        USD                       126.58
    
    60 rows selected.

SQL> SELECT AI SHOWSQL 2025年の注文金額を月別、通貨別に集計し、月の昇順、通貨コードの昇順で表示してください。異なる通貨は合算しないでください。;

    RESPONSE
    ________________________________________________________________________________________
    SELECT TO_CHAR(TO_DATE(o.ORDER_TIME_TXT, 'YYYY-MM-DD'), 'YYYY-MM') AS ORDER_MONTH,
           o.CURRENCY_CODE,
           SUM(TO_NUMBER(o.AMOUNT_TXT)) AS TOTAL_AMOUNT
    FROM "BAD_AI_READY"."RAW_ORDERS" o
    WHERE TO_CHAR(TO_DATE(o.ORDER_TIME_TXT, 'YYYY-MM-DD'), 'YYYY') = '2025'
    GROUP BY TO_CHAR(TO_DATE(o.ORDER_TIME_TXT, 'YYYY-MM-DD'), 'YYYY-MM'), o.CURRENCY_CODE
    ORDER BY ORDER_MONTH, o.CURRENCY_CODE
    
    1 row selected.

● Test 05 — PK/FK関係を利用した未注文顧客

「注文を一度もしていない顧客」という自然言語から、顧客を起点に注文を外部結合し、注文が存在しない行を数えるアンチJOINを生成できるかを確認します。
重要なのは、顧客と注文をCUSTOMER_IDで正しく関連付けていることです。

問い合わせ内容
SELECT AI 注文を一度もしていない顧客は何人ですか?;

想定回答

0

顧客と注文をCUSTOMER_IDで関連付け、注文が存在しない顧客が0人であればPASSです。

出力結果
    SQL> SELECT AI SHOWSQL 注文を一度もしていない顧客は何人ですか?;
    
    RESPONSE
    __________________________________________________________________________________
    SELECT COUNT(DISTINCT rc."CUSTOMER_ID") AS "Number_of_Customers_Without_Orders"
    FROM "BAD_AI_READY"."RAW_CUSTOMERS" rc
    LEFT JOIN "BAD_AI_READY"."RAW_ORDERS" ro ON rc."CUSTOMER_ID" = ro."CUSTOMER_ID"
    WHERE ro."ORDER_ID" IS NULL
    
    1 row selected.
    
    SQL> SELECT AI 注文を一度もしていない顧客は何人ですか?;
    
       Number_of_Customers_Without_Orders
    _____________________________________
                                        0
    
    1 row selected.

● Test 06 — 問い合わせコード、重大度、顧客JOIN

問い合わせ状態のコード値、重大度の数値変換、顧客とのFK関係を同時に使うケースです。個人の連絡先を出力しないことも自然言語で指定します。

問い合わせ内容
SELECT AI OPENまたはIN_PROGRESSの問い合わせのうち、
重大度4以上のものを顧客ごとに集計し、
顧客ID、顧客名、問い合わせ件数を表示してください。
件数の多い順、
同数の場合は顧客IDの昇順で表示してください。
メールアドレスと電話番号は表示しないでください。;

想定回答

顧客ID 顧客名 問い合わせ件数
3 Demo Customer 003 1
10 Demo Customer 010 1
13 Demo Customer 013 1
20 Demo Customer 020 1
25 Demo Customer 025 1
35 Demo Customer 035 1
48 Demo Customer 048 1

7行が一致し、OPENまたはIN_PROGRESS、重大度4以上、顧客JOINの条件がすべて入っていればPASSです。

出力結果
SQL> SELECT AI SHOWSQL OPENまたはIN_PROGRESSの問い合わせのうち、
  2  重大度4以上のものを顧客ごとに集計し、
  3  顧客ID、顧客名、問い合わせ件数を表示してください。
  4  件数の多い順、
  5  同数の場合は顧客IDの昇順で表示してください。
  6* メールアドレスと電話番号は表示しないでください。;

    RESPONSE
    _______________________________________________________________________________________________
    SELECT C."CUSTOMER_ID" AS "顧客ID", C."FULL_NAME" AS "顧客名", COUNT(ST."TICKET_ID") AS "問い合わせ件数"
    FROM "BAD_AI_READY"."SUPPORT_TICKETS" ST
    JOIN "BAD_AI_READY"."RAW_CUSTOMERS" C ON ST."CUSTOMER_ID" = C."CUSTOMER_ID"
    WHERE ST."TICKET_STATUS" IN ('OPEN', 'IN_PROGRESS')
    AND TO_NUMBER(ST."SEVERITY_TXT") >= 4
    GROUP BY C."CUSTOMER_ID", C."FULL_NAME"
    ORDER BY COUNT(ST."TICKET_ID") DESC, C."CUSTOMER_ID"
    
    1 row selected.

SQL> SELECT AI OPENまたはIN_PROGRESSの問い合わせのうち、
  2  重大度4以上のものを顧客ごとに集計し、
  3  顧客ID、顧客名、問い合わせ件数を表示してください。
  4  件数の多い順、
  5  同数の場合は顧客IDの昇順で表示してください。
  6* メールアドレスと電話番号は表示しないでください。;

       顧客ID 顧客名                     問い合わせ件数
    _______ ____________________ __________
          3 Demo Customer 003             1
         10 Demo Customer 010             1
         13 Demo Customer 013             1
         20 Demo Customer 020             1
         25 Demo Customer 025             1
         35 Demo Customer 035             1
         48 Demo Customer 048             1
    
    7 rows selected.

● Test 07 — 特徴量の意味と数値変換

CHURN_SCORE_TXTのコメントには、0.00から0.99の文字列で、高いほど離反傾向が高いことを記載しています。列名だけでは分からないスコアの意味を、Select AIが条件と集計へ反映できるかを確認します。

問い合わせ内容
SELECT AI 離反傾向スコアが0.80以上の顧客をセグメント別に集計し、
顧客数と平均顧客生涯価値を表示してください。
セグメントコードの昇順で表示し、
顧客名や連絡先は表示しないでください。;

想定回答

SEGMENT_CODE CUSTOMER_COUNT AVG_LIFETIME_VALUE
S1 2 3503.25
S2 5 2697.5
S3 3 1598.75

3行が一致し、離反傾向スコアと顧客生涯価値を数値として扱えているかをSHOWSQLで確認します。

出力結果
SQL> SELECT AI SHOWSQL 離反傾向スコアが0.80以上の顧客をセグメント別に集計し、
  2  顧客数と平均顧客生涯価値を表示してください。
  3  セグメントコードの昇順で表示し、
  4* 顧客名や連絡先は表示しないでください。;

    RESPONSE
    _________________________________________________________________________
    SELECT CF."SEGMENT_CODE" AS "SEGMENT_CODE",
           COUNT(CF."CUSTOMER_ID") AS "CUSTOMER_COUNT",
           AVG(TO_NUMBER(CF."LIFETIME_VALUE_TXT")) AS "AVG_LIFETIME_VALUE"
    FROM "BAD_AI_READY"."CUSTOMER_FEATURES" CF
    WHERE CF."CHURN_SCORE_TXT" >= '0.80'
    GROUP BY CF."SEGMENT_CODE"
    ORDER BY CF."SEGMENT_CODE"
    
    1 row selected.

SQL> SELECT AI 離反傾向スコアが0.80以上の顧客をセグメント別に集計し、
  2  顧客数と平均顧客生涯価値を表示してください。
  3  セグメントコードの昇順で表示し、
  4* 顧客名や連絡先は表示しないでください。;
    
    SEGMENT_CODE       CUSTOMER_COUNT    AVG_LIFETIME_VALUE
    _______________ _________________ _____________________
    S1                              2               3503.25
    S2                              5                2697.5
    S3                              3               1598.75
    
    3 rows selected.

Test 07の判定:条件付きPASS
RUNSQLの3行は想定回答と一致し、平均顧客生涯価値はTO_NUMBERで数値変換されました。一方、絞込み条件はCHURN_SCORE_TXT >= '0.80'であり、離反傾向スコアを文字列として比較しています。

なぜ注意が必要か
今回はすべての値が0.00から0.99の同じ書式なので、文字列の辞書順と数値順が一致しました。しかし、桁数やスコア範囲が変わると安全ではありません。例えば2.010.0を文字列で比較すると、辞書順では10.0が小さいと判定される可能性があります。

対応策

  1. 自然言語に「離反傾向スコアと顧客生涯価値は数値として変換してください」と明記する
  2. SHOWSQLTO_NUMBER(CHURN_SCORE_TXT) >= 0.80になっていることを確認する
  3. 実運用ではスコアをNUMBERで保持するか、型付きAI向けViewを用意する

修正プロンプト例です。

SELECT AI SHOWSQL
離反傾向スコアが0.80以上の顧客をセグメント別に集計し、
顧客数と平均顧客生涯価値を表示してください。
離反傾向スコアと顧客生涯価値は数値として変換して計算してください。
セグメントコードの昇順で表示し、顧客名や連絡先は表示しないでください。;

参照SQLでは次のように数値比較しています。

TO_NUMBER(
  CHURN_SCORE_TXT,
  '0D99',
  q'[NLS_NUMERIC_CHARACTERS='.,']'
) >= 0.80

● Test 08-A — 3表JOINと数量変換(gpt-3.5-turbo)

顧客、注文、注文明細の3表を2本のFKに沿って結合するテストです。今回のケースの中では、constraints=trueによる関係情報の効果を最も確認しやすい問い合わせです。

問い合わせ内容
SELECT AI 日本の有効な顧客が購入した商品の総数量をSKU別に集計し、
総数量の多い順、同数の場合はSKUの昇順で上位10件を表示してください。;

想定回答

SKU TOTAL_QUANTITY
SKU-0001 2
SKU-0002 2
SKU-0037 2
SKU-0038 2
SKU-0049 2
SKU-0050 2
SKU-0061 2
SKU-0062 2
SKU-0073 2
SKU-0074 2

3表を2本のFKに沿ってJOINし、COUNTRY_CODE='JP'STATUS_TXT='ACTIVE'の両方を適用した結果が、この10行と一致すればPASSです。

SHOWSQLとRUNSQLの結果
SQL> SELECT AI SHOWSQL 日本の有効な顧客が購入した商品の総数量をSKU別に集計し、
  2  総数量の多い順、同数の場合はSKUの昇順で上位10件を表示してください。;

RESPONSE
_____________________________________________________________________________
SELECT OL."SKU",
       SUM(TO_NUMBER(OL."QUANTITY_TXT")) AS "TOTAL_QUANTITY"
FROM "BAD_AI_READY"."RAW_ORDER_LINES" OL
JOIN "BAD_AI_READY"."RAW_ORDERS" O ON OL."ORDER_ID" = O."ORDER_ID"
JOIN "BAD_AI_READY"."RAW_CUSTOMERS" C ON O."CUSTOMER_ID" = C."CUSTOMER_ID"
WHERE C."COUNTRY_CODE" = 'JP'
GROUP BY OL."SKU"
ORDER BY "TOTAL_QUANTITY" DESC, OL."SKU" ASC
FETCH FIRST 10 ROWS ONLY

1 row selected.

SQL> SELECT AI 日本の有効な顧客が購入した商品の総数量をSKU別に集計し、
  2  総数量の多い順、同数の場合はSKUの昇順で上位10件を表示してください。;

SKU            TOTAL_QUANTITY
___________ _________________
SKU-0001                    2
SKU-0002                    2
SKU-0013                    2
SKU-0014                    2
SKU-0025                    2
SKU-0026                    2
SKU-0037                    2
SKU-0038                    2
SKU-0049                    2
SKU-0050                    2

10 rows selected.

Test 08-Aの総合判定:FAIL(SHOWSQLで検出済み)
自然言語では「日本の有効な顧客」と指定しましたが、生成SQLにはCOUNTRY_CODE='JP'だけが入り、STATUS_TXT='ACTIVE'が欠落しました。そのため非アクティブ顧客の購入明細も集計され、想定回答とは異なるSKUが結果へ混入しています。

ただし、3表の選択、2本のJOIN、数量の数値変換、国コード条件は正しく生成されています。今回不足したのは、「有効な顧客」という業務用語をACTIVEへ対応付ける意味情報です。構造メタデータの利用は成功し、業務用語の解釈で失敗したケースとして整理します。

想定回答と実行結果の差

区分 上位10 SKU
想定回答 SKU-0001, SKU-0002, SKU-0037, SKU-0038, SKU-0049, SKU-0050, SKU-0061, SKU-0062, SKU-0073, SKU-0074
Test 08-Aの結果 SKU-0001, SKU-0002, SKU-0013, SKU-0014, SKU-0025, SKU-0026, SKU-0037, SKU-0038, SKU-0049, SKU-0050

● Test 08-B — LLMだけをgpt-5.4-nanoへ変更して再実行

Test 08-Aでは、プロンプトをコード値まで具体化する方法も考えられます。しかし今回は、メタデータやプロンプトを変更せず、LLMの違いだけを確認するため、AI Profileのモデルをgpt-5.4-nanoへ変更して同じ問い合わせを再実行しました。

変更していないものは次のとおりです。

BAD_AI_READYスキーマ   : 同じ
テーブル・カラムコメント: 同じ
PK/FK                  : 同じ
AI Profileの対象表     : 同じ
日本語プロンプト        : 同じ
変更したもの            : LLMのみ

1) AI Profileのモデルをgpt-5.4-nanoへ変更

AI Profileの所有者でDBMS_CLOUD_AI.SET_ATTRIBUTEを実行し、model属性だけを変更します。対象表、コメント、制約など、ほかのProfile属性は変更しません。

BEGIN
  DBMS_CLOUD_AI.SET_ATTRIBUTE(
    profile_name    => 'BAD_AI_READY_OPENAI',
    attribute_name  => 'model',
    attribute_value => 'gpt-5.4-nano'
  );
END;
/
出力結果
PL/SQL procedure successfully completed.

2) AI Profileのモデルを確認

SELECT attribute_value AS model
FROM user_cloud_ai_profile_attributes
WHERE profile_name = 'BAD_AI_READY_OPENAI'
  AND attribute_name = 'model';
出力結果
MODEL
_______________
gpt-5.4-nano

3) 同じ自然言語を再実行

SELECT AI 日本の有効な顧客が購入した商品の総数量をSKU別に集計し、
総数量の多い順、
同数の場合はSKUの昇順で上位10件を表示してください。;
出力結果
SKU            TOTAL_QUANTITY
___________ _________________
SKU-0001                    2
SKU-0002                    2
SKU-0037                    2
SKU-0038                    2
SKU-0049                    2
SKU-0050                    2
SKU-0061                    2
SKU-0062                    2
SKU-0073                    2
SKU-0074                    2

10 rows selected.

想定回答とSKU、数量、並び順がすべて一致しました。ただし、結果が偶然一致した可能性を除くため、SHOWSQLで生成SQLも確認します。

4) SHOWSQLで生成SQLを確認

SELECT AI SHOWSQL 日本の有効な顧客が購入した商品の総数量をSKU別に集計し、
総数量の多い順、
同数の場合はSKUの昇順で上位10件を表示してください。;
出力結果
SELECT
  ol."SKU" AS "SKU",
  SUM(TO_NUMBER(ol."QUANTITY_TXT")) AS "TOTAL_QUANTITY"
FROM
  "BAD_AI_READY"."RAW_ORDERS" o
  JOIN "BAD_AI_READY"."RAW_ORDER_LINES" ol
    ON ol."ORDER_ID" = o."ORDER_ID"
  JOIN "BAD_AI_READY"."RAW_CUSTOMERS" c
    ON c."CUSTOMER_ID" = o."CUSTOMER_ID"
WHERE
  UPPER(c."STATUS_TXT") = 'ACTIVE'
  AND UPPER(c."COUNTRY_CODE") = 'JP'
GROUP BY
  ol."SKU"
ORDER BY
  "TOTAL_QUANTITY" DESC,
  ol."SKU" ASC
FETCH FIRST 10 ROWS ONLY

生成SQLを確認すると、想定した条件がすべて含まれています。

確認項目 生成SQL 判定
3表の選択 RAW_CUSTOMERSRAW_ORDERSRAW_ORDER_LINES PASS
顧客と注文のJOIN CUSTOMER_ID PASS
注文と注文明細のJOIN ORDER_ID PASS
数量の数値変換 SUM(TO_NUMBER(QUANTITY_TXT)) PASS
有効顧客の条件 UPPER(STATUS_TXT)='ACTIVE' PASS
日本の条件 UPPER(COUNTRY_CODE)='JP' PASS
集計・並び順・上位10件 GROUP BYORDER BYFETCH FIRST 10 ROWS ONLY PASS
想定回答との一致 SKU、数量、並び順が一致 PASS

Test 08-Bの総合判定:PASS
RUNSQLの回答が想定回答と一致しただけでなく、SHOWSQLでも、3表JOIN、数量の数値変換、ACTIVE条件、JP条件、並び順、上位10件の取得を確認できました。

Test 08-AとTest 08-Bを並べると、AI Ready Dataのメタデータは同じでも、使用するLLMによって業務用語の解釈と生成SQLが変わることが分かります。

比較項目 Test 08-A Test 08-B
LLM gpt-3.5-turbo gpt-5.4-nano
メタデータ 同じ 同じ
日本語プロンプト 同じ 同じ
3表JOIN PASS PASS
ACTIVE条件 欠落 あり
想定回答 不一致 一致
総合判定 FAIL PASS

この結果から、Select AIの精度は、スキーマのAI Ready化だけで決まるのではなく、使用するLLMの自然言語理解とSQL生成能力にも影響されることが分かります。一方、Test 08の1問だけでモデル全体の優劣は判断できないため、モデルを変更する場合は同じTestセットで回帰テストする必要があります。

● Test 08から見えた改善候補と今回確認できたこと

Test 08-Aの条件漏れを受け、最初にLLMだけを変更して再実行したところ、Test 08-Bでは同じ日本語プロンプトで想定回答と一致し、SHOWSQLでも必要な条件を確認できました。

一方、LLM変更だけに依存すると、モデル更新や問い合わせ内容によって結果が変わる可能性があります。業務用語の定義を再利用可能な知識として持たせる方法も、引き続き検証する価値があります。

改善方法 今回の状況 次に確認すること
LLM差分確認 Test 08でのみ確認済みgpt-3.5-turboはFAIL、gpt-5.4-nanoはPASS Test 01〜Test 10を同じ条件で再実行し、正解率を比較する
コード値を明記したプロンプト 未実施 「有効」=ACTIVE、「日本」=JPを明記するとモデル差を減らせるか
additional_instructions 未実施 AI Profileへ「有効な顧客」=STATUS_TXT='ACTIVE'を用語集として登録し、元の曖昧なプロンプトで正解するか
Annotations / AI Enrichment 未実施 ALIASDESCRIPTIONSAMPLE VALUESなどで業務用語と物理カラムを対応付けられるか
Select AI Feedback 未実施 誤ったSQLと正しいSQL・業務定義を登録すると、類似プロンプトで改善するか
AI向け型付きView 未実施 文字列の日付・金額・数量を正しい型で公開すると、型変換の注意を減らせるか

今回の結果は、より高性能なLLMへ変更すればすべて解決する、という結論ではありません。AI Ready Data、LLM選択、業務用語の定義、想定回答を使った回帰テストを組み合わせることが重要です。

● Test 09 — 改善SQLで追加した鮮度と出所

改善SQLで追加したSOURCE_SYSTEMUPDATED_ATを自然言語から参照します。SkillのCurrentCorrelatedを改善した列が、実際の問い合わせにも利用できることを確認します。

問い合わせ内容
SELECT AI 注文データについて、
提供元システムごとの行数と最終更新日時を表示し、
提供元システムの昇順で表示してください。;

想定回答

SOURCE_SYSTEM ROW_COUNT LATEST_UPDATED_AT
PART2_CSV 100 改善SQLを実行した日時

UPDATED_ATは実行時刻によって変わるため固定値では比較せず、SOURCE_SYSTEM='PART2_CSV'、100行、MAX(UPDATED_AT)がNULLでないことを確認します。

出力結果
SQL> SELECT AI SHOWSQL 注文データについて、
  2  提供元システムごとの行数と最終更新日時を表示し、
  3* 提供元システムの昇順で表示してください。;

    RESPONSE
    _______________________________________________________________________________________
    SELECT "SOURCE_SYSTEM" AS "提供元システム", COUNT(*) AS "行数", MAX("UPDATED_AT") AS "最終更新日時"
    FROM "BAD_AI_READY"."RAW_ORDERS"
    GROUP BY "SOURCE_SYSTEM"
    ORDER BY "提供元システム" ASC
    
    1 row selected.


SQL> SELECT AI 注文データについて、
  2  提供元システムごとの行数と最終更新日時を表示し、
  3* 提供元システムの昇順で表示してください。;

    提供元システム          行数 最終更新日時
    ____________ ______ __________________________________
    PART2_CSV       100 21-JUL-26 04.49.30.416340000 AM
    
    1 row selected.

● Test 10 — コメントによる空表の意味理解

最後に、「外部出力データ」という業務用語から、0行のEMPTY_EXPORTを選択できるかを確認します。データがない表でも、コメントによって用途を説明できることがポイントです。

問い合わせ内容
SELECT AI 外部出力データは何件ありますか?;

想定回答

0

「外部出力データ」という業務用語からEMPTY_EXPORTを選択し、0件を返せばPASSです。

出力結果
SQL> SELECT AI SHOWSQL 外部出力データは何件ありますか?;

    RESPONSE
    _____________________________________
    SELECT COUNT(*) AS "外部出力データ件数"
    FROM "BAD_AI_READY"."EMPTY_EXPORT"
    
    1 row selected.

SQL> SELECT AI 外部出力データは何件ありますか?;

       外部出力データ件数
    ____________
               0
    
    1 row selected.

● Select AIテストの総合判定

今回の検証は、次の2段階で行いました。

評価単位 結果
gpt-3.5-turboによるTest 01〜Test 10のベースライン PASS 7件、条件付きPASS 2件、FAIL 1件、想定回答との一致9 / 10件
Test 08をgpt-5.4-nanoで再実行 RUNSQLSHOWSQLの両方でPASS
gpt-5.4-nanoによるTest 01〜Test 10の一括回帰テスト 未実施

Test 03とTest 07は結果自体は参照SQLと一致しましたが、暗黙変換または文字列比較を使用していたため、SQL品質上は条件付きPASSとしました。Test 08-AはACTIVE条件が欠落してFAILでしたが、同じメタデータと同じ日本語プロンプトのままLLMだけを変更したTest 08-Bでは、想定回答と一致し、SHOWSQLでも必要なすべての条件を確認できました。

今回の結果から、AI Ready化によって次の効果を確認できました。

  • 業務用語から対象表を選択できる
  • PK/FKに沿って2表・3表をJOINできる
  • コメントに記載した日付形式、金額、数量、コード値をSQL生成へ利用できる
  • 改善SQLで追加した鮮度・出所列を自然言語から参照できる
  • 機微情報を出力しない指示を反映できる

さらに、Select AIの回答品質には次の3層があることが分かりました。

役割
AI Ready Data コメント、PK/FK、鮮度、出所など、LLMが理解するためのメタデータを整備する
LLM 日本語の業務用語を条件やJOINへ変換してSQLを生成する
テストとレビュー SHOWSQLと想定回答で、生成SQLと回答結果の正誤を確認する

AI Readyは「生成SQLが必ず正しい」という保証ではありません。また、ある1問で正解したLLMが、すべての問い合わせで常に正しいとも限りません。そのため、Select AIの機能確認は次の順序で行うのが安全です。

  1. 人が確認した参照SQLで想定回答を作成する
  2. SELECT AI SHOWSQLで使用表、JOIN、WHERE条件、型変換、出力列を確認する
  3. SELECT AI RUNSQLで実行する
  4. 想定回答と行数、値、並び順を比較してPASS / FAILを判定する
  5. LLMやAI Profileを変更した場合は、同じTestセットを回帰テストする

今回のようにTest番号、想定回答、実行結果、判定理由を残しておくことで、LLMやAI Profileの変更前後を同じ基準で比較できます。

次回は、gpt-5.4-nanoでTest 01〜Test 10を一括再実行するとともに、AI Profileのadditional_instructions、Annotations / AI Enrichment、Select AI Feedbackを使い、曖昧な日本語の業務用語をどこまで再利用可能な知識としてSelect AIへ渡せるかを確認します。

次回タイトル案:oracle-ai-ready-data Skill 第3回: LLMとadditional_instructionsで曖昧な日本語NL2SQLを改善してみてみた

■ まとめ

今回は、コメントや制約などのメタデータを意図的に欠落させたBAD_AI_READYスキーマを作成し、oracle-ai-ready-data Skillによる評価、改善SQLのレビュー・実行、再評価、Select AIによる機能確認までを行いました。

結果をまとめると次のとおりです。

項目 改善前 改善後
総合スコア 0.22 0.97
Mandatory comment gate fail pass
テーブルコメント 0% 100%
カラムコメント 0% 100%
PK coverage 0% 100%
Relationship coverage 0% 100%
Freshness coverage 0% 100%
Source metadata coverage 0% 100%
Broad data grant absence 62.5% 100%

6 Dimensionで見ると、Contextual と Correlated が 0.00 だった改善前に対し、
改善後は Correlated を除く4項目が 1.00 に到達しています。
ai_ready_radar.png

今回の検証で、データの行が正しくても、意味、関係、鮮度、出所、機微性がメタデータとして説明されていなければ、AI Readyとは評価されにくいことが分かりました。また、Skillが生成した改善候補は、そのまま実行するのではなく、業務オーナーやDBAがコメント内容、キー、権限、更新方式をレビューして具体化することが重要です。

改善後は、コメント必須ゲートを通過し、Select AIでも表コメント、カラムコメント、PK/FKを利用した表選択やJOINを確認できました。一方、gpt-3.5-turboでは暗黙変換、文字列比較、条件漏れも確認されました。Test 08についてLLMだけをgpt-5.4-nanoへ変更したところ、同じ日本語プロンプトで想定回答と一致し、SHOWSQLでも必要な3表JOIN、ACTIVE条件、JP条件、数量変換を確認できました。

なお、今回の主対象はSelect AI / NL2SQL向けのscan Profileです。AI_DOCUMENTSには本文CLOBがありますが、VECTOR列、embedding、Vector Index、検索品質までは扱っていません。RAGについては、検索対象文書のchunking、embeddingの生成・更新、根拠URI、Vector Searchの精度を別途確認する必要があります。

ということで、BAD_AI_READYスキーマを改善し、AI Ready評価、Select AIの想定回答テスト、さらにLLM変更による生成SQLの差まで確認してみてみました。

■ 解説

初心者でもわかりやすく理解できるよう解説しています。セールストークにどーぞ

■ おまけ

おまけ.png

■ 参考情報

● oracle-ai-ready-data Skill

  • Oracle AI Ready Data Skill - GitHub
    Oracle DatabaseのスキーマやOracle AI機能の準備状況を、SQLclで収集したメタデータから評価するSkillです。Markdown形式とHTML形式の評価レポート、およびレビューを前提とした改善SQLを生成します。

  • BAD_AI_READY Part 2 v1.0.0
    本記事で使用したDDL、CSVデータ、改善SQL、検証SQL、Select AI用プロンプトを含む再現パッケージです。

  • BAD_AI_READY Part 2 ソース
    GitHub上でSQL、README、テストケース、CSVデータを個別に確認できます。

● Select AI

  • About Select AI
    Select AIの概要です。自然言語からのSQL生成・実行・説明、RAG、LLMとの対話などが説明されています。

  • Getting Started with Select AI
    AI Profileの作成、セッションへの設定、SELECT AIの基本的な利用手順を確認できます。

  • Select AI Concepts
    Select AIが利用するテーブル名、カラム名、データ型、コメント、制約などのメタデータについて説明されています。

  • Manage AI Profiles
    DBMS_CLOUD_AI.CREATE_PROFILEDBMS_CLOUD_AI.SET_PROFILE、対象オブジェクトやProfile属性の設定方法を確認できます。

  • Examples of Using Select AI
    RUNSQLSHOWSQLEXPLAINSQLNARRATEなど、Select AIアクションの実行例です。

  • DBMS_CLOUD_AI Package
    AI Profileの作成・管理やSelect AIで使用するDBMS_CLOUD_AIパッケージのリファレンスです。

  • Customize AI Responses with Role and Additional Instructions
    AI Profileへ永続的な業務ルール、用語、レスポンス制約を設定するadditional_instructionsの利用例です。

  • AI Enrichment
    ALIASDESCRIPTIONSAMPLE VALUESなどのAnnotationによって、物理スキーマへ業務上の意味を追加する考え方です。

  • Select AI Feedback
    生成SQLの正誤や修正SQLを登録し、類似する将来のプロンプトへヒントとして利用する機能です。

  • Select AI and Select AI Agent Capability Matrix

● Oracle Databaseのメタデータ整備

  • COMMENT
    COMMENT ON TABLECOMMENT ON COLUMNを使用して、テーブルやカラムの説明をデータ・ディクショナリへ登録する方法です。

  • Constraint
    主キー、外部キー、一意制約、CHECK制約などの定義を確認できます。

  • ALTER TABLE
    既存表へのカラム追加、制約追加、列定義変更などで使用するALTER TABLEのリファレンスです。

  • DBMS_STATS
    表やカラムのオプティマイザ統計を収集・管理するDBMS_STATSパッケージのリファレンスです。

● Oracle SQLcl

  • Loading a File
    SQLclのLOADコマンドを使用して、ローカルまたはクラウド上のCSVファイルをOracle Databaseへロードする方法です。

● 関連記事

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?