sqloracle-databasefunctionsubtype

Is there a PL/SQL function to count the number of n subtypes of a super type?


Is there a function in PL/SQL that can count the number of n subtypes of a table (supertype)?

I've tried the following:

select
    count(distinct value(t1))
from table t1;

select
    count(distinct treat(value(t1))
from table t1;

Basically, if a table has 6 subtypes, I would like a query that could output 6.


Solution

  • Oracle Setup:

    CREATE TYPE parent_type AS OBJECT( id NUMBER ) NOT FINAL;
    CREATE TYPE child1_type UNDER parent_type ( c1 NUMBER );
    CREATE TYPE child2_type UNDER parent_type ( c2 NUMBER ) NOT FINAL;
    CREATE TYPE child3_type UNDER child2_type ( c3 NUMBER );
    
    CREATE TABLE test_data ( value parent_type );
    
    INSERT INTO test_data ( value )
      SELECT parent_type( 1 ) FROM DUAL UNION ALL
      SELECT child1_type( 2, 1 ) FROM DUAL UNION ALL
      SELECT child1_type( 3, 1 ) FROM DUAL UNION ALL
      SELECT child1_type( 4, 1 ) FROM DUAL UNION ALL
      SELECT child2_type( 5, 2 ) FROM DUAL UNION ALL
      SELECT child2_type( 6, 2 ) FROM DUAL UNION ALL
      SELECT child3_type( 7, 3, 1 ) FROM DUAL UNION ALL
      SELECT child3_type( 8, 3, 1 ) FROM DUAL UNION ALL
      SELECT child3_type( 9, 3, 1 ) FROM DUAL;
    

    Query 1:

    If you know the type hierarchy then you can build a query manually using the fact that TREAT( object AS type ) will return NULL if the object you are passing is not of that type and can use a CASE statement and start from the leaves of the hierarchy tree and process the types from deepest inheritance depth through to the parent type:

    SELECT COUNT( DISTINCT
             CASE
             WHEN TREAT( value AS child3_type ) IS NOT NULL
               THEN 'child3_type' -- deepest subtype
             WHEN TREAT( value AS child2_type ) IS NOT NULL
               THEN 'child2_type' -- supertype of child3_type, subtype of parent_type
             WHEN TREAT( value AS child1_type ) IS NOT NULL
               THEN 'child1_type' -- subtype of parent_type
             ELSE 'parent_type'
             END
           ) AS num_types
    FROM   test_data
    

    Query 2:

    If you have access to the SYS.ANYDATA type then you can get the type of the object:

    SELECT COUNT(
             DISTINCT
             SYS.ANYDATA.getTypeName(
               SYS.ANYDATA.convertObject( value )
             )
           ) AS num_types
    FROM   test_data
    

    Output:

    Both give the same output:

    | NUM_TYPES |
    | --------: |
    |         4 |
    

    db<>fiddle here