Select AI can translate natural language prompts into SQL. The quality of the generated SQL depends not only on the prompt, but also on the metadata available for the database objects.
This becomes visible when a schema uses technical or meaningless names. A developer may know that table E contains employees, table T contains training records, and table R contains recognition records. But from the metadata alone, names do not explain much.
In this post, I use a small three-table schema to show the difference between running Select AI without useful business context and running it after adding database annotations with giving the required business context. The example is simple: the goal is not to test complex SQL generation, but to show how missing semantics can lead to wrong or misleading results.
The demo has four steps:
- Create a schema with generic table and column names
- Configure Select AI for the schema
- Run natural language queries and review the generated results
- Add annotations and run the same queries again
Please consider that constraints can help Select AI understand relationships between tables, but they do not explain the business meaning of columns. Annotations add this missing semantic layer.
A short review: Schema annotations and AI enrichment
Schema annotations are additional metadata that can be attached to database objects such as tables, columns, views, materialized views, and indexes. They are stored centrally in the database and can be used by applications, tools, metadata repositories, and AI-assisted features.
An annotation can be either a name or a name-value pair. The annotation name is mandatory, while the value is optional. Both are free-form text fields. Multiple annotations can be specified for the same schema object.
More information can be found in the Database Development Guide
From an availability perspective, annotations are part of Oracle Database 23ai/26ai and are also available in Oracle Database 19c starting with Release Update 19.28.
Whereas, AI Enrichment the tool-assisted workflow in SQL Developer for VS Code has the same goal. It helps to add, refine, and optimize schema, table, and column metadata, including meaningful labels and descriptions for database objects.

Picture 1: AI enrichment in SQL Developer for VS Code.
More information can found in the AI Enablement Guide.
Therefore, there are two ways to add this kind of context:
- Manually, with Schema annotations
- Interactively with AI enrichment in SQL Developer for VS Code
In this demo, I use SQL statements so that the example is easy to reproduce.
A short review: Select AI
Select AI provides natural language access to Oracle Database using large language models and embedding models. It supports natural-language-to-SQL generation, retrieval augmented generation, SQL explanation, and chat-style interactions with an LLM, depending on the configured profile and action.
A typical Select AI setup uses an AI profile. The profile defines information such as the provider, credential, region, enabled features, and the list of database objects that should be visible to Select AI.
Demonstration
Generic Schema Without Semantics
Let’s start with a small example. The schema contains three tables:
E – employee master data
T – training records
R – recognition records
The table relationships are defined with primary and foreign keys, but the table and column names intentionally do not describe the business meaning of the data.
DROP TABLE T;
DROP TABLE R;
DROP TABLE E;
-- Employee master
CREATE TABLE E (
c1 NUMBER CONSTRAINT e_pk PRIMARY KEY,
c2 VARCHAR2(100),
c3 VARCHAR2(100),
c4 VARCHAR2(20),
c5 DATE
);
INSERT INTO e VALUES (101, 'Alice Johnson', 'Finance', 'ACTIVE', DATE '2024-01-15');
INSERT INTO e VALUES (102, 'Brian Smith', 'Sales', 'PROMOTED', DATE '2023-06-10');
INSERT INTO e VALUES (103, 'Clara Davis', 'HR', 'ACTIVE', DATE '2022-09-05');
INSERT INTO e VALUES (104, 'David Wilson', 'IT', 'ONBOARDING', DATE '2025-02-01');
INSERT INTO e VALUES (105, 'Emma Brown', 'Finance', 'PROMOTED', DATE '2021-11-20');
-- Training records
CREATE TABLE t (
c1 NUMBER CONSTRAINT t_pk PRIMARY KEY,
c2 NUMBER NOT NULL,
c3 VARCHAR2(100),
c4 VARCHAR2(20),
c5 DATE,
CONSTRAINT t_e_fk FOREIGN KEY (c2) REFERENCES e(c1)
);
INSERT INTO t VALUES (1, 101, 'Leadership Fundamentals', 'COMPLETED', DATE '2025-01-10');
INSERT INTO t VALUES (2, 102, 'Advanced Sales Strategy', 'COMPLETED', DATE '2025-02-15');
INSERT INTO t VALUES (3, 103, 'Leadership Fundamentals', 'IN_PROGRESS', DATE '2025-03-01');
INSERT INTO t VALUES (4, 104, 'Cloud Security Basics', 'PLANNED', DATE '2025-04-20');
INSERT INTO t VALUES (5, 105, 'Leadership Fundamentals', 'COMPLETED', DATE '2024-12-12');
INSERT INTO t VALUES (6, 105, 'AI Innovation Workshop', 'COMPLETED', DATE '2025-02-28');
-- Recognition records
CREATE TABLE r (
z1 NUMBER CONSTRAINT r_pk PRIMARY KEY,
z2 NUMBER NOT NULL,
z3 VARCHAR2(20),
z4 DATE,
CONSTRAINT r_e_fk FOREIGN KEY (z2) REFERENCES e(c1)
);
INSERT INTO r VALUES (1, 101, 'Teamwork', DATE '2025-03-15');
INSERT INTO r VALUES (2, 102, 'Leadership', DATE '2025-03-18');
INSERT INTO r VALUES (3, 105, 'Innovation', DATE '2025-04-02');
INSERT INTO r VALUES (4, 101, 'Innovation', DATE '2025-04-05');
INSERT INTO r VALUES (5, 103, 'Teamwork', DATE '2025-04-11');
COMMIT;
Select AI Setup
In the following example Autonomous Database and a pre-created database user A_TEST is used.
First, enable the database user A_TEST to use Select AI.
BEGIN
DBMS_CLOUD_AI.DROP_PROFILE(
profile_name => 'GENAI',
force => TRUE
);
END;
/
Next, create an AI profile that uses the default COHERE model on OCI. Make sure that you add “annotations” and “constraints” to “true”. More about DBMS_CLOUD_AI can be found in the documentation DBMS_CLOUD_AI package.
BEGIN
DBMS_CLOUD_AI.CREATE_PROFILE(
profile_name => 'GENAI',
attributes => '{
"provider": "oci",
"credential_name": "OCI$RESOURCE_PRINCIPAL",
"region": "eu-frankfurt-1",
"conversation": "false",
"annotations": "true",
"comments": "true",
"constraints": "true",
"object_list_mode": "all",
"temperature": 0,
"seed": 42,
"object_list": [
{"owner": "A_TEST", "name": "E"},
{"owner": "A_TEST", "name": "T"},
{"owner": "A_TEST", "name": "R"}
]
}'
);
END;
/
You may check your AI profiles with the data dictionary view USER_CLOUD_AI_PROFILE_ATTRIBUTES.
In the next step set the AI profile in your database session with
begin
dbms_cloud_ai.set_profile (profile_name=> 'GENAI');
end;
/
Select AI queries without AND with schema annotations
In the next step we execute 5 statements with Select AI, the first time without annotations and then with annotations.
We also use SHOWSQL to display the SQL statement for a natural language prompt e.g.
SELECT AI SHOWSQL Show active employees;
Query 1: Show active employees.
Without schema annotations:
Select AI only sees column names E.C1, E.C2, E.C3, E.C4, E.C5. The rows are correct, but the meaning is wrong. Finance and HR are shown as employee name.
SELECT AI Show active employees;
Employee_ID Employee_Name Employee_Department
----------- -------------- -------------------
101 Finance ACTIVE
103 HR ACTIVE
SELECT AI SHOWSQL Show active employees;
RESPONSE
------------------------------------------------
SELECT
"e"."C1" AS "Employee_ID",
"e"."C3" AS "Employee_Name",
"e"."C4" AS "Employee_Department"
FROM "A_TEST"."E" "e"
WHERE UPPER("e"."C4") = UPPER('active')
With schema annotations:
SELECT AI Show active employees;
SQL:
SELECT
e."C1" AS employee_id,
e."C2" AS employee_name,
e."C3" AS department,
e."C4" AS employee_status,
e."C5" AS hire_date
FROM
"A_TEST"."E" e
WHERE
UPPER(e."C4") = UPPER('active')
Result:
Employee_ID Employee_Name Department Employee_status Hire_date
----------- --------------- --------------- --------------- ---------
101 Alice Johnson Finance ACTIVE 15-JAN-24
103 Clara Davis HR ACTIVE 05-SEP-22
Query 2: Show employees who completed Leadership Fundamentals training.
Without schema annotations:
The result is false negative.
SELECT AI Show employees who completed Leadership Fundamentals training;
SQL:
SELECT
"E"."C3" AS employee_name,
"T"."C4" AS training_name
FROM "A_TEST"."E" "E"
JOIN "A_TEST"."T" "T"
ON "E"."C1" = "T"."C2"
WHERE UPPER("T"."C4") = UPPER('Leadership Fundamentals')
Result:
no rows selected
With schema annotations:
SELECT AI Show employees who completed Leadership Fundamentals training;
SQL:
SELECT
e."C2" AS employee_name,
t."C3" AS training_course_name,
t."C5" AS training_date
FROM
"A_TEST"."E" e
JOIN "A_TEST"."T" t ON e."C1" = t."C2"
WHERE
UPPER(e."C4") = UPPER('ACTIVE')
AND t."C3" = 'Leadership Fundamentals'
AND UPPER(t."C4") = UPPER('COMPLETED')
Result:
eemployee_name training_course_name training_date
-------------- ----------------------- ------------------------
Alice Johnson Leadership Fundamentals 10-JAN-25
Query 3: Show employees recognized for Innovation.
Without schema annotations:
SELECT AI Show employees who received Innovation recognition;
SQL:
SELECT
e."C3" AS employee_name,
e."C4" AS employee_id
FROM "A_TEST"."E" e
WHERE UPPER(e."C3") = UPPER('Innovation recognition')
Result
no rows
With schema annotations:
SELECT AI Show employees who received Innovation recognition;
SQL:
SELECT
"E"."C2" AS "employee_name"
FROM
"A_TEST"."E" "E"
JOIN "A_TEST"."R" "R" ON "E"."C1" = "R"."Z2"
WHERE
"R"."Z3" = 'Innovation'
Result:
employee_name
-------------
Emma Brown
Alice Johnson
Query 4: Count recognition by department.
Without schema annotations:
This is the wrong aggregation dimension. E.C4 is the employee status.
SELECT AI Count recognitions by employee department;
SQL:
SELECT
"E"."C4" AS department,
COUNT("R"."Z1") AS recognition_count
FROM
"A_TEST"."E" "E"
JOIN "A_TEST"."R" "R" ON "E"."C1" = "R"."Z2"
GROUP BY
"E"."C4"
Result:
DEPARTMENT RECOGNITION_COUNT
-------------------- -----------------
ACTIVE 3
PROMOTED 2
With schema annotations:
SELECT AI Count recognitions by employee department;
SQL:
SELECT
e."C3" AS department,
COUNT(r."Z1") AS recognition_count
FROM
"A_TEST"."E" e
JOIN "A_TEST"."R" r ON e."C1" = r."Z2"
GROUP BY
e."C3"
Result
Department Recognition_Count
--------------- -----------------
Finance 3
Sales 1
HR 1
Query 5: Show promoted employees with completed AI training.
Without schema annotations:
The result is False Negative.
SELECT AI show promoted employees who completed AI Innovation Workshop training;
SQL:
SELECT
"e"."C1" AS "Employee_ID",
"e"."C3" AS "Employee_Name",
"t"."C2" AS "Promotion_Status"
FROM "A_TEST"."E" "e"
JOIN "A_TEST"."T" "t" ON "e"."C1" = "t"."C2"
WHERE UPPER("e"."C4") = UPPER('AI Innovation Workshop') AND "t"."C5" IS NOT NULL
Result:
no rows selected
With schema annotations:
SELECT AI show promoted employees who completed AI Innovation Workshop training;
SQL:
SELECT
e."C2" AS employee_name,
e."C4" AS employee_status,
t."C3" AS training_course_name,
t."C4" AS training_status
FROM
"A_TEST"."E" e
JOIN "A_TEST"."T" t ON e."C1" = t."C2"
WHERE
UPPER(e."C4") = UPPER('PROMOTED')
AND t."C3" = 'AI Innovation Workshop'
AND t."C4" = 'COMPLETED'
Result:
employee_name employee_status training_course_name training_status
------------- --------------- -------------------------- --------------------
Emma Brown PROMOTED AI Innovation Workshop COMPLETED
Schema annotations on the underlying tables and columns
You can add annotations to schema objects when you create new objects (using the CREATE statements) or modify existing objects (using the ALTER statements). Here is the code how to add annotations to table E and the related columns with the ALTER TABLE command.
We add a description and a display annotation to each column and to the table. The idea is to have the following result:
Table A = employees
Column C1 = employee_id
Column C2 = employee_name
Column C3 = department
Column C4 = employee_status
Column C5 = hire_date
ALTER TABLE e ANNOTATIONS (
ADD IF NOT EXISTS display 'employees',
ADD IF NOT EXISTS description 'Employee master table. One row per employee.'
);
ALTER TABLE e MODIFY (
c1 ANNOTATIONS (
ADD IF NOT EXISTS display 'employee_id',
ADD IF NOT EXISTS description 'Unique employee identifier. Primary key. Used to join employees to training and recognition records.'
),
c2 ANNOTATIONS (
ADD IF NOT EXISTS display 'employee_name',
ADD IF NOT EXISTS description 'Full name of the employee.'
),
c3 ANNOTATIONS (
ADD IF NOT EXISTS display 'department',
ADD IF NOT EXISTS description 'Business department of the employee, for example Finance, Sales, HR, or IT.'
),
c4 ANNOTATIONS (
ADD IF NOT EXISTS display 'employee_status',
ADD IF NOT EXISTS description 'Current employee status. Example values are ACTIVE, PROMOTED, and ONBOARDING.'
),
c5 ANNOTATIONS (
ADD IF NOT EXISTS display 'hire_date',
ADD IF NOT EXISTS description 'Date when the employee was hired.'
)
);
Now we add annotations to table T and the table columns.
The result looks like
Table T = training records
Column C1 = training id
Column C2 = employee id
Column C3 = training course name such as Leadership Fundamentals, AI Innovation Workshop etc.
Column C4 = training status such as COMPLETED, IN_PROGRESS, and PLANNED
Column C5 = training date
ALTER TABLE t ANNOTATIONS (
ADD IF NOT EXISTS display 'training_records',
ADD IF NOT EXISTS description 'Training records for employees. One row per employee training course.'
);
ALTER TABLE t MODIFY (
c1 ANNOTATIONS (
ADD IF NOT EXISTS display 'training_record_id',
ADD IF NOT EXISTS description 'Unique training record identifier. Primary key.'
),
c2 ANNOTATIONS (
ADD IF NOT EXISTS display 'employee_id',
ADD IF NOT EXISTS description 'Employee identifier. Foreign key to A.C1. Used to join training records to employees.'
),
c3 ANNOTATIONS (
ADD IF NOT EXISTS display 'training_course_name',
ADD IF NOT EXISTS description 'Name of the training course, for example Leadership Fundamentals, Advanced Sales Strategy, Cloud Security Basics, or AI Innovation Workshop.'
),
c4 ANNOTATIONS (
ADD IF NOT EXISTS display 'training_status',
ADD IF NOT EXISTS description 'Status of the training record. Example values are COMPLETED, IN_PROGRESS, and PLANNED.'
),
c5 ANNOTATIONS (
ADD IF NOT EXISTS display 'training_date',
ADD IF NOT EXISTS description 'Date associated with the training course or planned training.'
)
);
In the last step, we add annotation to table R.
The result is the following:
Table R = recognition records
Column Z1 = recognition id
Column Z2 = employee id
Column Z3 = recognition category such as Teamwork, Leadership, and Innovation
Column Z4 = recognition date
ALTER TABLE r ANNOTATIONS (
ADD IF NOT EXISTS display 'recognition_records',
ADD IF NOT EXISTS description 'Recognition records for employees. One row per recognition award or recognition category.'
);
ALTER TABLE r MODIFY (
z1 ANNOTATIONS (
ADD IF NOT EXISTS display 'recognition_record_id',
ADD IF NOT EXISTS description 'Unique recognition record identifier. Primary key.'
),
z2 ANNOTATIONS (
ADD IF NOT EXISTS display 'employee_id',
ADD IF NOT EXISTS description 'Employee identifier. Foreign key to A.C1. Used to join recognition records to employees.'
),
z3 ANNOTATIONS (
ADD IF NOT EXISTS display 'recognition_category',
ADD IF NOT EXISTS description 'Recognition category or award type. Example values are Teamwork, Leadership, and Innovation.'
),
z4 ANNOTATIONS (
ADD IF NOT EXISTS display 'recognition_date',
ADD IF NOT EXISTS description 'Date when the employee received the recognition.'
)
);
You may check the result with data dictionary view USER_ANNOTATIONS_USAGE. Here we only display the annotation_value for the the annotation_name ‘DISPLAY’.
SELECT object_name || '.'|| column_name object,
annotation_name,
annotation_value
FROM user_annotations_usage
WHERE object_name IN ('E', 'T', 'R') and annotation_name ='DISPLAY'
ORDER BY object_name, column_name, annotation_name;
OBJECT ANNOTATION_NAME ANNOTATION_VALUE
---------- --------------- ------------------------
E.C1 DISPLAY employee_id
E.C2 DISPLAY employee_name
E.C3 DISPLAY department
E.C4 DISPLAY employee_status
E.C5 DISPLAY hire_date
E. DISPLAY employees
R.Z1 DISPLAY recognition_record_id
R.Z2 DISPLAY employee_id
R.Z3 DISPLAY recognition_category R.Z4 DISPLAY recognition_date
R. DISPLAY recognition_records
T.C1 DISPLAY training_record_id
T.C2 DISPLAY employee_id
T.C3 DISPLAY training_course_name
T.C4 DISPLAY training_status
T.C5 DISPLAY training_date
T. DISPLAY training_records
Summary
For many applications, it is important to maintain additional property metadata for database objects such as tables, views, table columns, indexes, and domains. Schema annotations enable your applications to store and retrieve additional user-specific metadata about database objects and table columns.
For example with schema annotations it’s much easier for select AI to interpret the schema objects. Schema annotations provide the business context, reduce ambiguity, and improve the quality of generated SQL. For complex prompts or highly abbreviated schemas, reviewing the generated SQL with SHOWSQL remains a useful best practice.
