Database & Development

SQL Metadata Queries for Dynamic Schema Discovery

Problem

Applications often need to discover database schema information programmatically for dynamic form generation, data validation, or automated documentation. Hard-coding table and column names creates maintenance overhead when schema changes occur. Dynamic report builders, data import tools, and admin interfaces require runtime access to table structures.

Solution

Use Oracle data dictionary views (USER_TAB_COLUMNS, ALL_TAB_COLUMNS, USER_CONSTRAINTS, USER_INDEXES) to query schema metadata programmatically. Build reusable PL/SQL functions that return table structures, column definitions, and constraint information.

Implementation

-- Get all columns for a table
SELECT
    column_name,
    data_type,
    data_length,
    data_precision,
    data_scale,
    nullable,
    data_default
FROM user_tab_columns
WHERE table_name = 'MY_TABLE'
ORDER BY column_id;

Dynamic Column List Function:

CREATE OR REPLACE FUNCTION get_table_columns (
    p_table_name IN VARCHAR2,
    p_delimiter IN VARCHAR2 DEFAULT ','
) RETURN VARCHAR2
IS
    l_columns VARCHAR2(4000);
BEGIN
    SELECT LISTAGG(column_name, p_delimiter)
           WITHIN GROUP (ORDER BY column_id)
    INTO l_columns
    FROM user_tab_columns
    WHERE table_name = UPPER(p_table_name);

    RETURN l_columns;
END get_table_columns;

Query Foreign Key Relationships:

SELECT
    ac.constraint_name,
    ac.table_name as child_table,
    acc.column_name as child_column,
    ac_pk.table_name as parent_table,
    acc_pk.column_name as parent_column
FROM all_constraints ac
JOIN all_cons_columns acc ON ac.constraint_name = acc.constraint_name
JOIN all_constraints ac_pk ON ac.r_constraint_name = ac_pk.constraint_name
JOIN all_cons_columns acc_pk ON ac_pk.constraint_name = acc_pk.constraint_name
WHERE ac_pk.table_name = 'MAIN_RECORDS'
  AND ac.constraint_type = 'R';

Metadata Cache Table:

CREATE TABLE metadata_cache (
    table_name VARCHAR2(128),
    column_name VARCHAR2(128),
    data_type VARCHAR2(106),
    is_nullable VARCHAR2(1),
    cached_date TIMESTAMP DEFAULT SYSTIMESTAMP,
    PRIMARY KEY (table_name, column_name)
);