Example Queries

Please note, that you have to deliver distinct data to ensure your graph is rendered correctly - see also this issue on GitHub. It is always a good idea to review your queries/data before you try to use it in a visualization ;-)

Oracle - Table EMP

This query is the base for the shipped sample data:

WITH
nodes AS ( --> START YOUR NODES QUERY HERE
  SELECT XMLELEMENT( "nodes", xmlattributes(
         empno        AS id
       , ename        AS label
       , sal          AS sizevalue
       , d.deptno     AS colorvalue
     --, d.dname      AS colorlabel    -- optional, used for the graph legend
     --, 'http://...' AS link          -- optional
     --, 'some text'  AS infostring    -- optional, rendered as tooltip
     --, 'false'      AS labelcircular -- optional, overwrites labelsCircular
     --, 'http://...' AS image         -- optional, background image for a node
     --, 'true'       AS "fixed"       -- optional | fixed, x and y are native
     --, 100          AS "x"           -- optional | D3 attributes, they must be
     --, 100          AS "y"           -- optional | lowercase
         ) ) AS xml_nodes
    FROM emp e join dept d on e.deptno = d.deptno --< STOP YOUR NODES QUERY HERE
),
links AS ( --> START YOUR LINKS QUERY HERE
  SELECT XMLELEMENT( "links", xmlattributes(
         empno          AS fromid
       , NVL(mgr,empno) AS toid
     --, 'dashed'       AS style       -- optional, solid, dotted or dashed
     --, 'red'          AS color       -- optional, must be a HTML color code
     --, 'some text'    AS infostring  -- optional, rendered as tooltip
         ) ) AS xml_links
    FROM emp --< STOP YOUR LINKS QUERY HERE
)
SELECT XMLSERIALIZE( DOCUMENT( XMLELEMENT( "data",
       ( SELECT XMLAGG( xml_nodes ) FROM nodes ),
       ( SELECT XMLAGG( xml_links ) FROM links ) ) ) INDENT ) AS single_clob_result
  FROM DUAL

Oracle - Data Model of Current Schema

With this query you can visualize the data model of the current schema. Tested on Oracle 11g. Some subqueries select more data then needed for the visualization - this could be a starting point for your own custom visualization.

ATTENTION: I tried to speed up the dictionary queries by using the with clause and filtering each subquery for the desired tables. Also, I tried to get the correct NOT NULL informations from the dictionary, since the nullable column in user_tab_columns does not reflect table level not null constraints. If you play around with the query to find an own solution you can run in massive performance problems when you join directly the dictionary views.

Many thanks to Adrian Billington for his excellent article about working with long columns.

--> The following helper function is needed to read the constraint search condition:
CREATE OR REPLACE FUNCTION get_long_search_condition( p_constraint_name IN VARCHAR2 )
   RETURN VARCHAR2
AS
   v_return LONG;
   CURSOR c_search_condition
   IS
        SELECT search_condition
          FROM user_constraints
         WHERE constraint_name = p_constraint_name;
BEGIN
   OPEN c_search_condition;
   FETCH c_search_condition INTO v_return;
   CLOSE c_search_condition;
   RETURN SUBSTR( v_return, 1, 4000 );
END;
WITH
tabs AS ( --> filter your tables here, all other queries use tabs as filter
  SELECT table_name
       , NVL( num_rows, 0 ) AS num_rows
       , CASE --> used for coloring the nodes in the graph
            WHEN table_name LIKE 'APEX$%' THEN 'APEX websheet apps'
            WHEN table_name LIKE 'DEMO%' THEN 'Sample database app'
            WHEN table_name in ('EMP', 'DEPT') THEN
               'The well known emp & dept tables'
            ELSE 'uncategorized tables'
         END
            AS table_group
    FROM user_tables
   WHERE table_name NOT LIKE 'PLSQL%'
),
cons AS (
  SELECT owner
       , constraint_name
       , constraint_type
       , table_name
       , get_long_search_condition( constraint_name ) AS search_condition
       , r_owner
       , r_constraint_name
       , delete_rule
       , status
    FROM user_constraints
   WHERE table_name IN (SELECT table_name FROM tabs)
),
concols AS (
  SELECT owner
       , constraint_name
       , table_name
       , column_name
       , position
    FROM user_cons_columns
   WHERE table_name IN (SELECT table_name FROM tabs)
),
connotnulls AS ( --> because of primary keys and not null check constraints we
                 --> have to select distinct here
  SELECT   DISTINCT table_name, column_name, nullable
     FROM (  SELECT c.table_name
                  , cc.column_name
                  , c.constraint_name
                  , c.constraint_type
                  , c.search_condition
                  , 'N' AS nullable
               FROM cons c
               JOIN concols cc ON c.constraint_name = cc.constraint_name
              WHERE     c.status = 'ENABLED'
                    AND (   c.constraint_type = 'P'
                         OR     c.constraint_type = 'C'
                            AND REGEXP_COUNT( TRIM( c.search_condition )
                                            ,    '^"{0,1}'
                                              || cc.column_name
                                              || '"{0,1}\s+is\s+not\s+null$'
                                            , 1
                                            , 'i' ) = 1 ))
),
tabcols AS (
  SELECT t.table_name
       , t.column_name
       , t.data_type
       , t.data_length
       , t.data_precision
       , t.data_scale
       , t.nullable AS nullable_dict
       --> dict does not recognize table level not null constraints:
       --> working with long columns:
       --> http://www.oracle-developer.net/display.php?id=430
       , NVL( n.nullable, 'Y' ) AS nullable_cons
    FROM user_tab_columns t
         LEFT JOIN connotnulls n
            ON     t.table_name = n.table_name
               AND t.column_name = n.column_name
   WHERE t.table_name IN (SELECT table_name FROM tabs)
),
fks AS (
   SELECT concols.table_name AS source_table
       , r_concols.table_name AS target_table
       , cons.status
       , tabcols.nullable_cons
    FROM cons
         JOIN concols
            ON cons.constraint_name = concols.constraint_name
          JOIN concols r_concols
            ON cons.r_constraint_name = r_concols.constraint_name
         JOIN tabcols
            ON     concols.table_name = tabcols.table_name
               AND concols.column_name = tabcols.column_name
   WHERE     cons.constraint_type = 'R'
         AND cons.status = 'ENABLED'
),
nodes AS ( --> START YOUR NODES QUERY HERE
  SELECT   XMLELEMENT( "nodes"
                     , xmlattributes( table_name AS id
                                    , table_name AS label
                                    , table_group AS colorvalue
                                    , num_rows AS sizevalue ) )
              AS xml_nodes
    FROM tabs --< STOP YOUR NODES QUERY HERE
),
links AS ( --> START YOUR LINKS QUERY HERE
  SELECT   XMLELEMENT( "links"
                     , xmlattributes( source_table AS fromid
                                    , target_table AS toid
                                    , CASE nullable_cons
                                         WHEN 'Y' THEN 'dashed'
                                         WHEN 'N' THEN 'solid'
                                      END AS style )
                     , status )
              AS xml_links
    FROM fks --< STOP YOUR LINKS QUERY HERE
)
SELECT XMLSERIALIZE( DOCUMENT( XMLELEMENT( "data",
       ( SELECT XMLAGG( xml_nodes ) FROM nodes ),
       ( SELECT XMLAGG( xml_links ) FROM links ) ) ) INDENT ) AS single_clob_result
  FROM DUAL