In Oracle, I want to use a sequence and not allow Insert on the column that uses the sequence

I want to make happen the same that happens when I do the following

CREATE TABLE "TEST1" 
(   
     "ID" NUMBER(10,0) GENERATED ALWAYS AS IDENTITY,
    "APPCODE" VARCHAR2(1)
);
  Table TEST1 created.
INSERT INTO TEST1 (ID, APPCODE) VALUES (1,'A');
   Error starting at line : 6 in command -
   INSERT INTO TEST1 (ID, APPCODE) VALUES (1,'A')
   Error at Command Line : 50 Column : 1
   Error report -
   SQL Error: ORA-32795: cannot insert into a generated always identity column
INSERT INTO TEST (APPCODE) VALUES ('A');
   1 row inserted.

but I want to use named sequences, created by me. I want the same behavior as when using the "ALWAYS" keyword (as in "GENERATED ALWAYS AS IDENTITY") and at the same time use my own named sequences, but I don't know how.

With named sequences, it seems to be impossible to avoid that an INSERT uses the ID COLUMN on the insert. But maybe there is a way? This is the question I'm asking. Below I create a named sequence and show the difference (I can't figure out how to prevent the ID column to be allowed on the insert).

CREATE SEQUENCE SEQ_TEST2 START WITH 1 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE;
    Sequence SEQ_TEST2 created.
INSERT INTO TEST2 (APPCODE) VALUES ('A'); /* This is ok */
   1 row inserted.
INSERT INTO TEST2 (ID,APPCODE) VALUES (1928,'A'); /* This is NOT ok */
   1 row inserted.

The second insert above is what I want to prevent from happening, it shouldn't be possible to insert on the ID column. I don't care how to prevent it to happen, doesn't have to be the same way that the "ALWAYS" keyword on the TEST1 table works, but I would like to prevent it from happening. Anyone knows please how to to it?


Solution 1:

When you define a column as a identity column, Oracle automatically creates a sequence, you just don't get to choose the name. You can view the name of the sequence that was created and will be used to populate the identity in the DATA_DEFAULT column of the ALL_TAB_COLS table.

SELECT owner,
       table_name,
       column_name,
       data_default
  FROM all_tab_cols
 WHERE identity_column = 'YES';

Solution 2:

Why do you thing that while using IDENTITY you do not use a SEQUENCE?

Check the documentation or the example below

CREATE TABLE "TEST1" 
(   
     "ID" NUMBER(10,0) GENERATED ALWAYS AS IDENTITY,
    "APPCODE" VARCHAR2(1)
);

For this table Oracle creates a sequence for you under the over:

EXPLAIN PLAN  SET STATEMENT_ID = 'jara1' into   plan_table  FOR
insert into TEST1 (APPCODE) values ('x');
---    
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL')); 

-----------------------------------------------------------------------------------------
| Id  | Operation                | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |              |     1 |   100 |     1   (0)| 00:00:01 |
|   1 |  LOAD TABLE CONVENTIONAL | TEST1        |       |       |            |          |
|   2 |   SEQUENCE               | ISEQ$$_75209 |       |       |            |          |
-----------------------------------------------------------------------------------------

Or check the dictionary

select SEQUENCE_NAME from USER_TAB_IDENTITY_COLS
where table_name = 'TEST1';

SEQUENCE_NAME                                                                                                                   
---------------
ISEQ$$_75209

In identity_options you can define the sequence options.

By selection ALWAYS or BY DEAFULT [ON NULL] you can adjust what is posible / now allowed to use in insert (I'm not sure from you description what is your aim).