Thursday, December 28, 2017

READ privilege in Oracle 12c

Starting with Oracle 12c we can now use READ object privilege to enable the users to query database tables, views, materialized views and synonyms. With this new READ object privilege, users can still query the objects like SELECT object privilege, but no more locks on the objects are possible.
 
 
demo@ORCL> create table t as select * from scott.dept;
 
Table created.
 
demo@ORCL> grant READ ON t to scott;
 
Grant succeeded.
 
demo@ORCL> conn scott/tiger
Connected.
scott@ORCL> select count(*) from demo.t;
 
  COUNT(*)
----------
         4
 
scott@ORCL> lock table demo.t in exclusive mode;
lock table demo.t in exclusive mode
                *
ERROR at line 1:
ORA-01031: insufficient privileges
 
 
scott@ORCL> begin
  2     for x in (select * from demo.t for update of deptno)
  3     loop
  4             null;
  5     end loop;
  6  end;
  7  /
        for x in (select * from demo.t for update of deptno)
                                     *
ERROR at line 2:
ORA-06550: line 2, column 31:
PL/SQL: ORA-01031: insufficient privileges
ORA-06550: line 2, column 12:
PL/SQL: SQL Statement ignored
 
 
scott@ORCL>
 
Now let’s remove the READ privilege and grant the SELECT privilege.
 
demo@ORCL> revoke READ on t from scott;
 
Revoke succeeded.
 
demo@ORCL> grant SELECT on t to scott;
 
Grant succeeded.
 
With this SELECT privilege, users can still query the objects.
 
demo@ORCL> conn scott/tiger
Connected.
scott@ORCL> select count(*) from demo.t;
 
  COUNT(*)
----------
         4
 
But lock the rows in the table are possible through SELECT privileges.
 
scott@ORCL> lock table demo.t in exclusive mode;
 
Table(s) Locked.
 
scott@ORCL> rollback;
 
Rollback complete.
 
scott@ORCL> begin
  2     for x in (select * from demo.t for update of deptno)
  3     loop
  4             null;
  5     end loop;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
scott@ORCL> rollback;
 
Rollback complete.
 
scott@ORCL> conn demo/demo
Connected.
demo@ORCL> select grantor,table_name,grantee,privilege
  2  from user_tab_privs_made
  3  where grantor='DEMO'
  4  and table_name ='T'
  5  /
 
GRANTOR    TABLE_NAME           GRANTEE    PRIVILEGE
---------- -------------------- ---------- ----------
DEMO       T                    SCOTT      SELECT
 
demo@ORCL> revoke select on t from scott;
 
Revoke succeeded.
 
demo@ORCL> grant read on t to scott;
 
Grant succeeded.
 
demo@ORCL> select grantor,table_name,grantee,privilege
  2  from user_tab_privs_made
  3  where grantor='DEMO'
  4  and table_name ='T'
  5  /
 
GRANTOR    TABLE_NAME           GRANTEE    PRIVILEGE
---------- -------------------- ---------- ----------
DEMO       T                    SCOTT      READ
 
demo@ORCL>

Thursday, December 21, 2017

gather_plan_statistics hint for parallel sqls

Had discussed enough about the gather_plan_statistics hint to validate the cardinality estimates, however this need to be revisited for Parallel sql execution in the database.
demo@ORA12C> alter session set statistics_level=all;
 
Session altered.
 
demo@ORA12C> set serveroutput off
demo@ORA12C> select /*+ parallel(b,4) */ count(*) from big_table b;
 
  COUNT(*)
----------
   1000000
 
demo@ORA12C> select * from table(dbms_xplan.display_cursor(format=>'ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------
SQL_ID  gqr17qtmdmsmq, child number 0
-------------------------------------
select /*+ parallel(b,4) */ count(*) from big_table b
 
Plan hash value: 2894119656
 
----------------------------------------------------------------------------------------------
| Id  | Operation              | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |           |      1 |        |      1 |00:00:01.97 |      20 |
|   1 |  SORT AGGREGATE        |           |      1 |      1 |      1 |00:00:01.97 |      20 |
|   2 |   PX COORDINATOR       |           |      1 |        |      4 |00:00:01.97 |      20 |
|   3 |    PX SEND QC (RANDOM) | :TQ10000  |      0 |      1 |      0 |00:00:00.01 |       0 |
|   4 |     SORT AGGREGATE     |           |      0 |      1 |      0 |00:00:00.01 |       0 |
|   5 |      PX BLOCK ITERATOR |           |      0 |    941K|      0 |00:00:00.01 |       0 |
|*  6 |       TABLE ACCESS FULL| BIG_TABLE |      0 |    941K|      0 |00:00:00.01 |       0 |
----------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   6 - access(:Z>=:Z AND :Z<=:Z)
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
   - Degree of Parallelism is 4 because of table property
 
 
28 rows selected.
 
demo@ORA12C>
 
As you can see from the parallel execution plan the majority of the rows in the plan have 0 in the A-rows column, this is caused by the nature of parallel execution and how it interacts with the FORMAT we requested in the DBMS_XPLAN.DISPLAY_CURSOR method. The FORMAT parameter value ‘ALLSTATS LAST’ request the execution statistics of the last execution of the cursor be shown.
 
In a parallel execution the last process to execute the cursor is the Query coordinator (QC), typically this QC will execute a small number of operations in the execution plan, while the majority of the operations in the plan was done by the parallel execution server process. So when we issue the DBMS_XPLAN.DISPLAY_CURSOR and ask for the last execution we only get the information about the operations in the plan that the QC actually executed. In this case the only operation that QC did was return the final result to our SQL*Plus session, which is why the line 0 and 1 and 2 have entries in the A-rows column.
 
In order to see A-rows values for all the operations in the plan, we have to use the FORMAT value as ALLSTATS ALL, which will show you the execution statistics for ALL executions of the cursor.
 
demo@ORA12C> set linesize 250
demo@ORA12C> alter session set statistics_level=all;
 
Session altered.
 
demo@ORA12C> set serveroutput off
demo@ORA12C> select /*+ parallel(b,4) */ count(*) from big_table b;
 
  COUNT(*)
----------
   1000000
 
demo@ORA12C> select * from table(dbms_xplan.display_cursor(format=>'ALLSTATS ALL'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------
SQL_ID  gqr17qtmdmsmq, child number 1
-------------------------------------
select /*+ parallel(b,4) */ count(*) from big_table b
 
Plan hash value: 2894119656
 
------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name      | Starts | E-Rows | Cost (%CPU)| E-Time   |    TQ  |IN-OUT| PQ Distrib | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |           |      1 |        |  1421 (100)|          |        |      |            |      1 |00:00:03.74 |      20 |      0 |
|   1 |  SORT AGGREGATE        |           |      1 |      1 |            |          |        |      |            |      1 |00:00:03.74 |      20 |      0 |
|   2 |   PX COORDINATOR       |           |      1 |        |            |          |        |      |            |      4 |00:00:03.74 |      20 |      0 |
|   3 |    PX SEND QC (RANDOM) | :TQ10000  |      0 |      1 |            |          |  Q1,00 | P->S | QC (RAND)  |      0 |00:00:00.01 |       0 |      0 |
|   4 |     SORT AGGREGATE     |           |      4 |      1 |            |          |  Q1,00 | PCWP |            |      4 |00:00:14.84 |   19247 |  18570 |
|   5 |      PX BLOCK ITERATOR |           |      4 |   1000K|  1421   (1)| 00:00:01 |  Q1,00 | PCWC |            |   1000K|00:00:14.83 |   19247 |  18570 |
|*  6 |       TABLE ACCESS FULL| BIG_TABLE |     55 |   1000K|  1421   (1)| 00:00:01 |  Q1,00 | PCWP |            |   1000K|00:00:14.83 |   19247 |  18570 |
------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1
   6 - SEL$1 / B@SEL$1
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   6 - access(:Z>=:Z AND :Z<=:Z)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - (#keys=0) COUNT()[22]
   2 - SYS_OP_MSR()[10]
   3 - (#keys=0) SYS_OP_MSR()[10]
   4 - (#keys=0) SYS_OP_MSR()[10]
   5 - (rowset=1019)
   6 - (rowset=1019)
 
Note
-----
   - Degree of Parallelism is 4 because of table property
 
 
43 rows selected.
 
demo@ORA12C>
 
We should be very careful about the A-Rows listed here, since those values listed in the execution plan will be cumulative (incremented on every execution)
Running the same sql three times in the session, produced the output (cumulative result in A-Rows columns) like this.
 
demo@ORA12C> alter session set statistics_level=all;
 
Session altered.
 
demo@ORA12C> set serveroutput off
demo@ORA12C> select /*+ parallel(b,4) */ count(*) from big_table b;
 
  COUNT(*)
----------
   1000000
 
demo@ORA12C> select /*+ parallel(b,4) */ count(*) from big_table b;
 
  COUNT(*)
----------
   1000000
 
demo@ORA12C> select /*+ parallel(b,4) */ count(*) from big_table b;
 
  COUNT(*)
----------
   1000000
 
demo@ORA12C> select * from table(dbms_xplan.display_cursor(format=>'ALLSTATS ALL'));
 
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------
SQL_ID  gqr17qtmdmsmq, child number 0
-------------------------------------
select /*+ parallel(b,4) */ count(*) from big_table b
 
Plan hash value: 2894119656
 
------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name      | Starts | E-Rows | Cost (%CPU)| E-Time   |    TQ  |IN-OUT| PQ Distrib | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |           |      3 |        |  1421 (100)|          |        |      |            |      3 |00:00:08.27 |      62 |      0 |
|   1 |  SORT AGGREGATE        |           |      3 |      1 |            |          |        |      |            |      3 |00:00:08.27 |      62 |      0 |
|   2 |   PX COORDINATOR       |           |      3 |        |            |          |        |      |            |     12 |00:00:08.27 |      62 |      0 |
|   3 |    PX SEND QC (RANDOM) | :TQ10000  |      0 |      1 |            |          |  Q1,00 | P->S | QC (RAND)  |      0 |00:00:00.01 |       0 |      0 |
|   4 |     SORT AGGREGATE     |           |     11 |      1 |            |          |  Q1,00 | PCWP |            |     11 |00:00:29.82 |   53474 |  51594 |
|   5 |      PX BLOCK ITERATOR |           |     12 |   1000K|  1421   (1)| 00:00:01 |  Q1,00 | PCWC |            |   3000K|00:00:32.11 |   57739 |  55710 |
|*  6 |       TABLE ACCESS FULL| BIG_TABLE |    151 |   1000K|  1421   (1)| 00:00:01 |  Q1,00 | PCWP |            |   2758K|00:00:29.19 |   52765 |  51203 |
------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1
   6 - SEL$1 / B@SEL$1
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   6 - access(:Z>=:Z AND :Z<=:Z)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - (#keys=0) COUNT()[22]
   2 - SYS_OP_MSR()[10]
   3 - (#keys=0) SYS_OP_MSR()[10]
   4 - (#keys=0) SYS_OP_MSR()[10]
   5 - (rowset=1019)
   6 - (rowset=1019)
 
Note
-----
   - Degree of Parallelism is 4 because of table property
 
 
43 rows selected.
 
demo@ORA12C>

Thursday, August 17, 2017

IDENTITY columns - A deep dive analysis

 
Identity columns were introduced in Oracle 12c, this new feature allows you to specify that a column should be automatically populated from a system created sequence.
First - an example of a table without an identity column.
demo@ORA12C> create table transaction1(
  2     transaction_id int,
  3     holding_id int,
  4     transaction_type number,
  5     transaction_date date,
  6     credit_value number,
  7     debit_value number );
 
Table created.
 
demo@ORA12C> desc transaction1;
 Name                                Null?    Type
 ----------------------------------- -------- -----------
 TRANSACTION_ID                               NUMBER(38)
 HOLDING_ID                                   NUMBER(38)
 TRANSACTION_TYPE                             NUMBER
 TRANSACTION_DATE                             DATE
 CREDIT_VALUE                                 NUMBER
 DEBIT_VALUE                                  NUMBER
 
demo@ORA12C>
 
 
In its simples form, the Identity clause can be specified like this.
 
demo@ORA12C> create table transaction2(
  2     transaction_id int GENERATED AS IDENTITY,
  3     holding_id int,
  4     transaction_type number,
  5     transaction_date date,
  6     credit_value number,
  7     debit_value number );
 
Table created.
 
demo@ORA12C>
demo@ORA12C> desc transaction2;
 Name                                Null?    Type
 ----------------------------------- -------- -------------
 TRANSACTION_ID                      NOT NULL NUMBER(38)
 HOLDING_ID                                   NUMBER(38)
 TRANSACTION_TYPE                             NUMBER
 TRANSACTION_DATE                             DATE
 CREDIT_VALUE                                 NUMBER
 DEBIT_VALUE                                  NUMBER
 
demo@ORA12C>
 
 
Note that a NOT NUL constraint has been automatically created for the TRANSACTION_ID column.
A sequence is created with a system created name ISEQ$$_<object_id>, where object_id is the object_id of the table.
demo@ORA12C> select object_id
  2  from user_objects
  3  where object_name ='TRANSACTION2' ;
 
 OBJECT_ID
----------
     87436
 
demo@ORA12C>
demo@ORA12C> select SEQUENCE_NAME from user_sequences ;
 
SEQUENCE_NAME
---------------
ISEQ$$_87436
 
demo@ORA12C>
 
 
By default, the GENERATED AS IDENTITY clause implicitly include the ALWAYS keyword, i.e GENERATED ALWAYS AS IDENTITY.  When the ALWAYS keyword is specified it is not possible to explicitly include values for the identity column in INSERT or UPDATE statement, doing so will produce error like this.
 
demo@ORA12C> insert into transaction2(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(55,1,0,sysdate,0,2);
insert into transaction2(transaction_id,holding_id,
                         *
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column
 
 
Values can also be generated automatically if no values are specified explicitly, using the following syntax.
 
 
demo@ORA12C> create table transaction3(
  2     transaction_id int GENERATED BY DEFAULT AS IDENTITY,
  3     holding_id int,
  4     transaction_type number,
  5     transaction_date date,
  6     credit_value number,
  7     debit_value number );
 
Table created.
 
 
Unlike the GENERATED AS IDENTITY clause, using GENERATED BY DEFAULT AS IDENTITY we can insert the transaction_id column explicitly like this.
 
 
demo@ORA12C> insert into transaction3(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(55,1,0,sysdate,0,2);
 
1 row created.
 
 
Or we could ignore the transaction_id column, where the database would take care of populating the values into this IDENTITY column.
 
 
demo@ORA12C> insert into transaction3(holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(1,0,sysdate,0,2);
 
1 row created.
demo@ORA12C> select * from transaction3 ;
 
TRANSACTION_ID HOLDING_ID TRANSACTION_TYPE TRANSACTION CREDIT_VALUE DEBIT_VALUE
-------------- ---------- ---------------- ----------- ------------ -----------
            55          1                0 31-JUL-2017            0           2
             1          1                0 31-JUL-2017            0           2
 
demo@ORA12C>
 
 
If you wish values to be generated when NULL value is supplied use GENERATED BY DEFAULT AS IDENTITY ON NULL option.
 
demo@ORA12C> create table transaction4(
  2     transaction_id int GENERATED BY DEFAULT ON NULL AS IDENTITY,
  3     holding_id int,
  4     transaction_type number,
  5     transaction_date date,
  6     credit_value number,
  7     debit_value number );
 
Table created.
 
 
With that, we can explicitly insert the values like this.
 
 
demo@ORA12C> insert into transaction4(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(55,1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> select * from transaction4;
 
TRANSACTION_ID HOLDING_ID TRANSACTION_TYPE TRANSACTION CREDIT_VALUE DEBIT_VALUE
-------------- ---------- ---------------- ----------- ------------ -----------
            55          1                0 31-JUL-2017            0           2
 
 
Else have an explicit NULL, and then the database will manipulate them for IDENTITY columns.
 
 
demo@ORA12C> insert into transaction4(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(NULL,1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> select * from transaction4;
 
TRANSACTION_ID HOLDING_ID TRANSACTION_TYPE TRANSACTION CREDIT_VALUE DEBIT_VALUE
-------------- ---------- ---------------- ----------- ------------ -----------
            55          1                0 31-JUL-2017            0           2
             1          1                0 31-JUL-2017            0           2
 
Else have an implicit NULL, and then the database will manipulate them for IDENTITY columns.
 
demo@ORA12C> insert into transaction4(holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> select * from transaction4;
 
TRANSACTION_ID HOLDING_ID TRANSACTION_TYPE TRANSACTION CREDIT_VALUE DEBIT_VALUE
-------------- ---------- ---------------- ----------- ------------ -----------
            55          1                0 31-JUL-2017            0           2
             1          1                0 31-JUL-2017            0           2
             2          1                0 31-JUL-2017            0           2
 
demo@ORA12C>
 
 
We can check which tables have IDENTITY columns from user_tables data dictionary.
 
demo@ORA12C> select table_name ,has_identity
  2  from user_tables
  3  where table_name like 'TRANSACTIO%'
  4  order by 1;
 
TABLE_NAME      HAS
--------------- ---
TRANSACTION1    NO
TRANSACTION2    YES
TRANSACTION3    YES
TRANSACTION4    YES
 
demo@ORA12C>
 
 
The ALTER Table statement supports the IDENTITY clause, but you cannot convert a non-identity column to an identity column.
 
Converting a non-identity column to identity column will return this error.
 
demo@ORA12C> alter table transaction1
  2  modify transaction_id GENERATED AS IDENTITY  ;
modify transaction_id GENERATED AS IDENTITY
       *
ERROR at line 2:
ORA-30673: column to be modified is not an identity column
 
 
Using ALTER Table statement, you can modify BY DEFAULT ON NULL clause into an ALWAYS clause.
 
demo@ORA12C> create table transaction5(
  2     transaction_id int GENERATED BY DEFAULT ON NULL AS IDENTITY primary key,
  3     holding_id int,
  4     transaction_type number,
  5     transaction_date date,
  6     credit_value number,
  7     debit_value number );
 
Table created.
 
demo@ORA12C> insert into transaction5(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(1,1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> insert into transaction5(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(2,1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> insert into transaction5(transaction_id,holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(3,1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> alter table transaction5 modify transaction_id
  2  GENERATED ALWAYS AS IDENTITY (start with limit value) ;
 
Table altered.
 
demo@ORA12C> insert into transaction5(holding_id,
  2     transaction_type,transaction_date,credit_value,debit_value)
  3     values(1,0,sysdate,0,2);
 
1 row created.
 
demo@ORA12C> select * from transaction5 ;
 
TRANSACTION_ID HOLDING_ID TRANSACTION_TYPE TRANSACTION CREDIT_VALUE DEBIT_VALUE
-------------- ---------- ---------------- ----------- ------------ -----------
             1          1                0 31-JUL-2017            0           2
             2          1                0 31-JUL-2017            0           2
             3          1                0 31-JUL-2017            0           2
             4          1                0 31-JUL-2017            0           2
 
demo@ORA12C>
 
START WITH LIMIT VALUE, can only be used with ALTER TABLE MODIFY. If you specify START WITH LIMIT VALUE, then Oracle Database locks the table and finds the maximum identity column value in the table and assigns the value as the sequence generator's high water mark.
 
While we cannot change a non-identity column into an identity column, we can convert an identity column into a non- identity column.
 
demo@ORA12C> alter table transaction5
  2  modify transaction_id
  3  drop identity ;
 
Table altered.
 
demo@ORA12C> select table_name ,has_identity
  2  from user_tables
  3  where table_name ='TRANSACTION5';
 
TABLE_NAME      HAS
--------------- ---
TRANSACTION5    NO
 
demo@ORA12C>
 
 
A Table cannot have more than one IDENTITY column.
 
demo@ORA12C> alter table transaction2
  2  add holding_id2 int
  3  generated always as identity;
add holding_id2 int
    *
ERROR at line 2:
ORA-30669: table can have only one identity column
 
IDENTITY column cannot be possible on non-numeric datatypes.
 
demo@ORA12C> alter table transaction
  2  add holding_id2 varchar2(10)
  3  generated always as identity;
generated always as identity
                           *
ERROR at line 3:
ORA-30675: identity column must be a numeric type
 
IDENTITY column cannot have Default values.
 
demo@ORA12C> alter table transaction2
  2  modify transaction_id default 55 ;
modify transaction_id default 55
       *
ERROR at line 2:
ORA-30674: identity column cannot have a default value
 
 
Create table as select does not inherit the IDENTITY property of a column in the source table.
 
demo@ORA12C> create table transaction6
  2  as
  3  select *
  4  from transaction2;
 
Table created.
 
demo@ORA12C> select table_name ,has_identity
  2  from user_tables
  3  where table_name ='TRANSACTION6';
 
TABLE_NAME      HAS
--------------- ---
TRANSACTION6    NO
 
demo@ORA12C>
 
 
When the table is dropped, the system created sequences will be dropped.
 
demo@ORA12C> select table_name ,has_identity,
  2     (select sequence_name
  3       from user_sequences s ,
  4                user_objects o
  5       where o.object_name = t.table_name
  6       and s.sequence_name like '%'||o.object_id) as sequence_name
  7  from user_tables t
  8  where has_identity = 'YES';
 
TABLE_NAME      HAS SEQUENCE_NAME
--------------- --- ---------------
TRANSACTION3    YES ISEQ$$_87440
TRANSACTION2    YES ISEQ$$_87438
TRANSACTION4    YES ISEQ$$_87442
 
demo@ORA12C> drop table transaction2 purge;
 
Table dropped.
 
demo@ORA12C> drop table transaction3 purge;
 
Table dropped.
 
demo@ORA12C> drop table transaction4 purge;
 
Table dropped.
 
demo@ORA12C> select table_name ,has_identity,
  2     (select sequence_name
  3       from user_sequences s ,
  4                user_objects o
  5       where o.object_name = t.table_name
  6       and s.sequence_name like '%'||o.object_id) as sequence_name
  7  from user_tables t
  8  where has_identity = 'YES';
 
no rows selected
 
demo@ORA12C>