Thursday, November 27, 2025

Creating and Using Table Hyperlink Groups in Oracle Autonomous Database

Table Hyperlinks in Oracle Autonomous Database provide a secure and convenient way to expose database objects and SQL query results through pre-authenticated URLs.
 
A recent enhancement extends this capability even further—Table Hyperlink Groups, which allow a single URL to represent multiple hyperlinks, each pointing to a table, view, or SQL query.
 
A Hyperlink Group allows you to bundle several table hyperlinks into a single group URL.
This is useful when: 
  • You want a single API endpoint that exposes multiple datasets
  • You want to simplify integration for downstream systems
  • You want to centralize access control under one pre-authenticated URL
  • You want to organize multiple SQL queries or objects logically
 
Below is a conceptual representation:



 
In this example, we will see how to create a Table Hyperlink Group using two data sources — one defined by a SQL query and the other referencing a table.
 
demo-user@ATP19C> declare
  2     l_status long;
  3  begin
  4     dbms_data_access.create_url(
  5             sqls => '[
  6                               {
  7                                     "name": "Employees table",
  8                                     "description": "Employees details",
  9                                     "sql_statement": " select empno,ename,hiredate,job,deptno from emp "
 10                               },
 11                               {
 12                                     "name": "Department table",
 13                                     "description": "Department details",
 14                                     "schema_name": "DEMO_USER",
 15                                     "schema_object_name": "DEPT"
 16                               }
 17                             ]'
 18             , result => l_status );
 19     dbms_output.put_line( l_status );
 20  end;
 21  /
{
  "status" : "SUCCESS",
  "id" : "JxfkVbJGWKYbD83nyC1wgcGTEuO2-6lzJDgN68V5Z7_Xf4OUTERg7CeUmXnU0RQh",
  "preauth_url" : "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/GW147LdUM4iIPKAsgNe2NIoByKCCGThJN4RKlrxHkcv7x_erMFkD8GQsgjprD64on7lQML_f2v8/data",
  "member_ids" :
  [
    "T_mxypj7jytHDoW5Li--q0Agxk_TKL3s2SZ46bJ0R6rMrDFa-X8lTLV5KjHsnEUk",
    "9I6oXda2SKvyDfTu8cCsr8c9T_BOUqIHT0kz4qgvWWAHG3dWYfoWmrDTdriNHp0J"
  ],
  "expiration_ts" : "2026-02-23T16:33:47.309Z"
}
 
PL/SQL procedure successfully completed.
 
demo-user@ATP19C>
 
Calling the group URL returns information about all member hyperlinks:
 
$ curl https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/GW147LdUM4iIPKAsgNe2NIoByKCCGThJN4RKlrxHkcv7x_erMFkD8GQsgjprD64on7lQML_f2v8/data
 
{
  "member_urls": [
    {
      "id": "T_mxypj7jytHDoW5Li--q0Agxk_TKL3s2SZ46bJ0R6rMrDFa-X8lTLV5KjHsnEUk",
      "name": "Employees table",
      "description": "Employees details"
    },
    {
      "id": "9I6oXda2SKvyDfTu8cCsr8c9T_BOUqIHT0kz4qgvWWAHG3dWYfoWmrDTdriNHp0J",
      "name": "Department table",
      "description": "Department details"
    }
  ]
}
 
 
To query data from a specific member in the group, supply its member_id:
 
$ curl https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/GW147LdUM4iIPKAsgNe2NIoByKCCGThJN4RKlrxHkcv7x_erMFkD8GQsgjprD64on7lQML_f2v8/data?member_id=9I6oXda2SKvyDfTu8cCsr8c9T_BOUqIHT0kz4qgvWWAHG3dWYfoWmrDTdriNHp0J
 
{
  "items": [
    {
      "DEPTNO": 10,
      "DNAME": "ACCOUNTING",
      "LOC": "NEW YORK"
    },
    {
      "DEPTNO": 20,
      "DNAME": "RESEARCH",
      "LOC": "DALLAS"
    },
    {
      "DEPTNO": 30,
      "DNAME": "SALES",
      "LOC": "CHICAGO"
    },
    {
      "DEPTNO": 40,
      "DNAME": "OPERATIONS",
      "LOC": "BOSTON"
    }
  ],
  "hasMore": false,
  "limit": 1000,
  "offset": 0,
  "count": 4,
  "links": [
    {
      "rel": "self",
      "href": "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/GW147LdUM4iIPKAsgNe2NIoByKCCGThJN4RKlrxHkcv7x_erMFkD8GQsgjprD64on7lQML_f2v8/data?member_id=9I6oXda2SKvyDfTu8cCsr8c9T_BOUqIHT0kz4qgvWWAHG3dWYfoWmrDTdriNHp0J"
    }
  ]
}
 
You can list all active hyperlinks — including groups — using json_table on dbms_data_access.list_active_urls:
 
demo-user@ATP19C> select *
  2  from
  3      json_table ( dbms_data_access.list_active_urls, '$[*]'
  4          columns (
  5              id
  6          , created_by
  7          , access_count
  8          , created path '$.created.timestamp()'
  9         , sql_statement
 10         , is_group_url
 11         )
 12*    ) ;
 
ID                                                                  CREATED_BY    ACCESS_COUNT    CREATED                            SQL_STATEMENT                                                       IS_GROUP_URL
___________________________________________________________________ _____________ _______________ __________________________________ ___________________________________________________________________ _______________
4PVOG8xtDt7CXzyhcKDcbAkW2rnXAWrzMAGt9W7D5IAOQwjPkrZbSGwRpsR7UNkP    DEMO_USER     1               15-NOV-25 03.54.44.291000000 PM     select * from emp where hiredate = :b1
JxfkVbJGWKYbD83nyC1wgcGTEuO2-6lzJDgN68V5Z7_Xf4OUTERg7CeUmXnU0RQh    DEMO_USER     4               25-NOV-25 04.33.47.333000000 PM                                                                        true
vzCL8zVM2Vj5Z0jGqhIb-56J7SlRvvnnqdelPVmUhOcRz2NbgG4BMVnGqY5dxCzU    DEMO_USER     4               16-NOV-25 03.57.59.390000000 PM     select * from emp where deptno = 10
v09slcWFCCHUgaH3XEEqqwMQClpSHabYebpYPaFp6Z3vsdnT6An8CZeCmfJv0-Oy    DEMO_USER     5               15-NOV-25 01.16.01.541000000 PM     select * from emp where deptno = :deptId
sfBVyDyNXhkwsodUQDHMnAaa4nrlAeVt4_2SE0F5yX0iMwfJNgUhScUlZ2Og8u0I    DEMO_USER     2               15-NOV-25 03.57.33.997000000 PM     select * from emp where hiredate >= to_date(:b1,'dd-mon-yyyy')
gTqfJcv0JfckskdR7eI77QCUrMcMe5N4k1iXeeWstlo6c7uKxXQbyQQPotFTi10E    DEMO_USER     12              21-NOV-25 02.58.18.205000000 PM     select * from emp where deptno = :b1 and job = :b2
 
6 rows selected.
 
is_group_url = TRUE identifies group hyperlinks
 
To list the member hyperlinks of an existing table hyperlink group, we can do the below pl/sql call.

 
demo-user@ATP19C> declare
  2     l_status clob;
  3  begin
  4     dbms_data_access.list_members(
  5         id => 'JxfkVbJGWKYbD83nyC1wgcGTEuO2-6lzJDgN68V5Z7_Xf4OUTERg7CeUmXnU0RQh'
  6         , result => l_status );
  7     dbms_output.put_line( l_status );
  8  end;
  9* /
{
  "members" :
  [
    {
      "id" : "T_mxypj7jytHDoW5Li--q0Agxk_TKL3s2SZ46bJ0R6rMrDFa-X8lTLV5KjHsnEUk",
      "consistent" : false,
      "sql_statement" : " select empno,ename,hiredate,job,deptno from emp ",
      "name" : "Employees table",
      "description" : "Employees details"
    },
    {
      "id" : "9I6oXda2SKvyDfTu8cCsr8c9T_BOUqIHT0kz4qgvWWAHG3dWYfoWmrDTdriNHp0J",
      "consistent" : false,
      "schema_name" : "DEMO_USER",
      "schema_object_name" : "DEPT",
      "name" : "Department table",
      "description" : "Department details"
    }
  ]
}
 
You can add an existing standalone hyperlink to a group using add_member:
 
demo-user@ATP19C> declare
  2     l_status clob ;
  3  begin
  4     dbms_data_access.add_member(
  5         id => 'JxfkVbJGWKYbD83nyC1wgcGTEuO2-6lzJDgN68V5Z7_Xf4OUTERg7CeUmXnU0RQh'
  6         , member_id =>'v09slcWFCCHUgaH3XEEqqwMQClpSHabYebpYPaFp6Z3vsdnT6An8CZeCmfJv0-Oy'
  7         , result => l_status );
  8     dbms_output.put_line( l_status );
  9  end;
 10* /
{
  "status" : "SUCCESS"
}
 
 
Verifying the update group members
 
demo-user@ATP19C> declare
  2     l_status clob;
  3  begin
  4     dbms_data_access.list_members(
  5         id => 'JxfkVbJGWKYbD83nyC1wgcGTEuO2-6lzJDgN68V5Z7_Xf4OUTERg7CeUmXnU0RQh'
  6         , result => l_status );
  7     dbms_output.put_line( l_status );
  8  end;
  9* /
{
  "members" :
  [
    {
      "id" : "T_mxypj7jytHDoW5Li--q0Agxk_TKL3s2SZ46bJ0R6rMrDFa-X8lTLV5KjHsnEUk",
      "consistent" : false,
      "sql_statement" : " select empno,ename,hiredate,job,deptno from emp ",
      "name" : "Employees table",
      "description" : "Employees details"
    },
    {
      "id" : "v09slcWFCCHUgaH3XEEqqwMQClpSHabYebpYPaFp6Z3vsdnT6An8CZeCmfJv0-Oy",
      "consistent" : false,
      "sql_statement" : " select * from emp where deptno = :deptId "
    },
    {
      "id" : "9I6oXda2SKvyDfTu8cCsr8c9T_BOUqIHT0kz4qgvWWAHG3dWYfoWmrDTdriNHp0J",
      "consistent" : false,
      "schema_name" : "DEMO_USER",
      "schema_object_name" : "DEPT",
      "name" : "Department table",
      "description" : "Department details"
    }
  ]
}
 
 
Accessing the New Member with Bind Variables, include them as query parameters:
 
$ curl --location 'https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/GW147LdUM4iIPKAsgNe2NIoByKCCGThJN4RKlrxHkcv7x_erMFkD8GQsgjprD64on7lQML_f2v8/data?member_id=v09slcWFCCHUgaH3XEEqqwMQClpSHabYebpYPaFp6Z3vsdnT6An8CZeCmfJv0-Oy&deptId=10'
 
{
  "items": [
    {
      "EMPNO": 7839,
      "ENAME": "KING",
      "JOB": "PRESIDENT",
      "HIREDATE": "1981-11-17T00:00:00",
      "SAL": 5000,
      "DEPTNO": 10
    },
    {
      "EMPNO": 7782,
      "ENAME": "CLARK",
      "JOB": "MANAGER",
      "MGR": 7839,
      "HIREDATE": "1981-06-09T00:00:00",
      "SAL": 2450,
      "DEPTNO": 10
    },
    {
      "EMPNO": 7934,
      "ENAME": "MILLER",
      "JOB": "CLERK",
      "MGR": 7782,
      "HIREDATE": "1982-01-23T00:00:00",
      "SAL": 1300,
      "DEPTNO": 10
    }
  ],
  "hasMore": false,
  "limit": 1000,
  "offset": 0,
  "count": 3,
  "links": [
    {
      "rel": "self",
      "href": "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/GW147LdUM4iIPKAsgNe2NIoByKCCGThJN4RKlrxHkcv7x_erMFkD8GQsgjprD64on7lQML_f2v8/data?member_id=v09slcWFCCHUgaH3XEEqqwMQClpSHabYebpYPaFp6Z3vsdnT6An8CZeCmfJv0-Oy&deptId=10"
    }
  ]
}
 
 
 
Table Hyperlink Groups provide: 
  •  A single, central access point for multiple data sources
  • Simplified integration with external applications
  • Easier control over permissions and lifecycle
  • Support for both object-based and SQL-query-based hyperlinks
  • Flexibility through bind variables 
This feature is particularly valuable when building lightweight APIs, exposing curated datasets, or integrating with downstream data pipelines.

Friday, November 21, 2025

Passing Bind Variables to Table Hyperlinks (Pre-Authenticated URLs) in Autonomous Database

Oracle Autonomous Database (ADB) continues to evolve rapidly with new capabilities that make data access more flexible, secure, and developer-friendly. One such recent enhancement is the ability to use bind variables in SQL queries within Table Hyperlinks (also known as Pre-Authenticated URLs).

 

This feature allows you to define SQL queries that include bind variables and then supply values for those variables either:

 

·         As default bind values at the time of hyperlink creation, or

·         As runtime URL parameters when calling the link.

 

This makes Pre-Authenticated URLs even more powerful, especially when building dashboards, external integrations, or lightweight query-driven APIs that depend on dynamic filtering.

 

In this article, we’ll walk through:

 

1.       What this feature is and why it’s useful

2.       How to create a Pre-Authenticated URL using bind variables

3.       How default bind values behave

4.       How to override bind values at runtime using query parameters

 

Why Bind Variables in Table Hyperlinks Matter


Previously, Table Hyperlinks supported only static SQL statements, which meant:

 

·         The logic was fixed

·         Filtering required separate hyperlinks

·         External services had no way to pass in parameters dynamically

 

With this enhancement, you can now create one hyperlink and let clients supply any number of dynamic bind values at runtime. This reduces maintenance, improves flexibility, and allows Table Hyperlinks to behave more like parameterized REST endpoints — without needing to implement a full REST service.

 

Creating a Table Hyperlink With Bind Variables

Let’s start with an example SQL query that contains two bind variables :b1 and :b2. 


demo-user@ATP19C> declare
  2     l_status long;
  3  begin
  4     dbms_data_access.create_url(
  5              sql_statement => q'# select * from emp where deptno = :b1 and job = :b2 #'
  6             , service_name =>'LOW'
  7             , default_bind_values => json_object('b1' value 20 ,'b2' value 'CLERK')
  8             , result => l_status );
  9     dbms_output.put_line( l_status );
 10  end;
 11  /


The key points here:

·         The SQL contains bind variables (:b1, :b2).

·         default_bind_values defines values that will be used if no runtime parameters are supplied.

·         A new pre-authenticated URL gets generated.

 

Sample output from the above PL/SQL block: 

{
  "status" : "SUCCESS",
  "id" : "gTqfJcv0JfckskdR7eI77QCUrMcMe5N4k1iXeeWstlo6c7uKxXQbyQQPotFTi10E",
  "preauth_url" : "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data",
  "expiration_ts" : "2026-02-19T14:58:18.187Z"

This URL can now be used from anywhere — scripts, dashboards, apps, or API clients. 

Accessing the Hyperlink Without Runtime Parameters

If you call the generated URL without adding any bind values in the query string, ADB will apply the default bind variable values (deptno = 20, job = 'CLERK'): 

$ curl --location 'https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data'

{
  "items": [
    {
      "EMPNO": 7369,
      "ENAME": "SMITH",
      "JOB": "CLERK",
      "MGR": 7902,
      "HIREDATE": "1980-12-17T00:00:00",
      "SAL": 800,
      "DEPTNO": 20
    },
    {
      "EMPNO": 7876,
      "ENAME": "ADAMS",
      "JOB": "CLERK",
      "MGR": 7788,
      "HIREDATE": "1987-05-23T00:00:00",
      "SAL": 1100,
      "DEPTNO": 20
    }
  ],
  "hasMore": false,
  "limit": 1000,
  "offset": 0,
  "count": 2,
  "links": [
    {
      "rel": "self",
      "href": "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data"
    }
  ]
}

This confirms that the default bind values were applied successfully. 

Overriding Bind Values at Runtime

The real strength of this feature lies in the ability to override bind variables dynamically.
All you need to do is append query parameters to the URL, using the same bind variable names.
 

1.       Changing a Single Bind Variable

 

For example, to override only b1:

 

$ curl --location 'https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data?b1=10'

 

{

  "items": [

    {

      "EMPNO": 7934,

      "ENAME": "MILLER",

      "JOB": "CLERK",

      "MGR": 7782,

      "HIREDATE": "1982-01-23T00:00:00",

      "SAL": 1300,

      "DEPTNO": 10

    }

  ],

  "hasMore": false,

  "limit": 1000,

  "offset": 0,

  "count": 1,

  "links": [

    {

      "rel": "self",

      "href": "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data?b1=10"

    }

  ]

}

 
Only the department number changed; the job remained 'CLERK' because we did not override b2.

 

2.       Changing Multiple Bind Variables
 
You can override as many bind values as needed:

 

$ curl --location 'https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data?b1=20&b2=MANAGER'

 

{

  "items": [

    {

      "EMPNO": 7566,

      "ENAME": "JONES",

      "JOB": "MANAGER",

      "MGR": 7839,

      "HIREDATE": "1981-04-02T00:00:00",

      "SAL": 2975,

      "DEPTNO": 20

    }

  ],

  "hasMore": false,

  "limit": 1000,

  "offset": 0,

  "count": 1,

  "links": [

    {

      "rel": "self",

      "href": "https://dataaccess.adb.us-ashburn-1.oraclecloudapps.com/adb/p/SSi8uslpyP4hikoPvJedQ9K6Jd-jGfC4hgY-tvdWWrqeu9TP_kPYoVkBu31kHadXqC3rdDDU4j4/data?b1=20&b2=MANAGER"

    }

  ]

}

 
With just one hyperlink, we can now produce entirely different result sets depending on the runtime parameters. 

Use Cases for Runtime Bind Variables

This enhancement opens the door for several powerful scenarios:


·         Dynamic filtering for dashboards

o    Single URL can drive multiple filtered views

·         External system integrations

o    Supply parameters from REST clients without changing SQL

·         Lightweight report endpoints

o    Customize responses without creating multiple URLs

·         Secure parameterized access

o    Bind variables reduce SQL injection risks

·         Simplified API behaviour

o    Acts like a parameterized GET endpoint

 

If you're building applications that need controlled, query-based access to ADB data, this feature dramatically reduces overhead.

 

Bind variable support for Table Hyperlinks adds a powerful new dimension to how data can be accessed and filtered in Autonomous Database. With just one hyperlink, you can:

·         Define parameterized SQL

·         Provide default bind values

·         Override those values at runtime

·         Drive flexible, dynamic data retrieval from external systems

 

This makes Pre-Authenticated URLs a versatile tool for lightweight data APIs, automated pipelines, and integration workflows.