Oracle SQL error "ORA-00984: column not allowed here" when trying to replace a column - sql

This question is not a duplicate from this one because even if the error messages are equal the answers there do not apply to my case.
I need to change a previous PK Id column defined as VARCHAR(36) NOT NULL to an incremental integer value. I'm trying to write a script to do this but when I run the alter table statement it fails with the error on the title.
The table is previously defined as:
CREATE TABLE journal_messages(
ID VARCHAR(36) NOT NULL, -- column to be changed
MESSAGE VARCHAR(2048) NOT NULL,
MESSAGE_TYPE VARCHAR(30) NOT NULL,
MSG_DATE TIMESTAMP NOT NULL,
MODULE_CODE INTEGER NOT NULL
);
ALTER TABLE journal_messages ADD (CONSTRAINT journal_messages_pk PRIMARY KEY (ID));
The script I'm running is:
DELETE FROM JOURNAL_MESSAGES;
ALTER TABLE JOURNAL_MESSAGES DROP COLUMN ID;
CREATE SEQUENCE journal_messages_seq START WITH 1;
ALTER TABLE JOURNAL_MESSAGES ADD (ID NUMBER(10) DEFAULT journal_messages_seq.nextval NOT NULL); -- error happens here
ALTER TABLE journal_messages ADD (
CONSTRAINT journal_messages_pk PRIMARY KEY (ID));
When I try to create a trigger it to update the incremental, it fails with SQL Error [4098] [42000]: ORA-04098: trigger 'TRG_SEQ_JOURNAL_MSG' is invalid and failed re-validation when I try to insert a new tuple:
ALTER TABLE JOURNAL_MESSAGES DROP COLUMN ID;
ALTER TABLE JOURNAL_MESSAGES ADD (ID NUMBER(10) NOT NULL);
create or replace trigger trg_seq_journal_msg
before insert on journal_messages
for each row
begin
:new.id := journal_messages_seq.nextval;
end;
/
INSERT INTO JOURNAL_MESSAGES (message, MESSAGE_TYPE, msg_date, MODULE_CODE) VALUES ('test', 'alteration', CURRENT_TIMESTAMP, '10');

Umm ... not like that, but like this:
once the table is empty, you don't have to drop the column - just modify its datatype
use a trigger to automatically set IDs value
If you were on 12c, you could have used identity column.
SQL> CREATE TABLE journal_messages(
2 ID VARCHAR(36) NOT NULL, -- column to be changed
3 MESSAGE VARCHAR(2048) NOT NULL,
4 MESSAGE_TYPE VARCHAR(30) NOT NULL,
5 MSG_DATE TIMESTAMP NOT NULL,
6 MODULE_CODE INTEGER NOT NULL
7 );
Table created.
SQL> delete from journal_Messages;
0 rows deleted.
SQL> alter table journal_messages modify (id number(10));
Table altered.
SQL> CREATE SEQUENCE journal_messages_seq START WITH 1;
Sequence created.
SQL> create or replace trigger trg_bi_joumes
2 before insert on journal_messages
3 for each row
4 begin
5 :new.id := journal_messages_seq.nextval;
6 end;
7 /
Trigger created.
SQL>
[EDIT: after reading your comment and saw your edition]
That still works OK - I literally copy/pasted your code and got this:
SQL> ALTER TABLE JOURNAL_MESSAGES DROP COLUMN ID;
Table altered.
SQL> ALTER TABLE JOURNAL_MESSAGES ADD (ID NUMBER(10) NOT NULL);
Table altered.
SQL> create or replace trigger trg_seq_journal_msg
2 before insert on journal_messages
3 for each row
4 begin
5 :new.id := journal_messages_seq.nextval;
6 end;
7 /
Trigger created.
SQL> INSERT INTO JOURNAL_MESSAGES (message, MESSAGE_TYPE, msg_date, MODULE_CODE) VALUES ('test', 'alteration', CURRENT_TIMESTAMP, '10')
2 ;
1 row created.
SQL>
As you can see, everything seems to be just fine. Try the following: recompile the trigger and show errors (if any; if so, please, post them here):
SQL> alter trigger trg_seq_journal_msg compile;
Trigger altered.
SQL> show err
No errors.
SQL>

Related

Oracle SQL - Trigger inserting into table passing null value from sequence

I have two table, TABLE_A and TABLE_B. When something gets inserted into TABLE_A there is a trigger that also inserts the data into TABLE_B. TABLE_A has an ID column which is populated using a sequence. This id then is also inserted into TABLE_B. This is the whole DDL for this:
CREATE TABLE "TABLE_A"
( "ID" NUMBER(8,0) NOT NULL ENABLE,
"COLUMN1" NUMBER(8,0) NOT NULL ENABLE,
"COLUMN2" NUMBER(4,0) NOT NULL ENABLE
)
/
CREATE TABLE "TABLE_B"
( "ID" NUMBER(8,0) NOT NULL ENABLE,
"COLUMN1" NUMBER(8,0) NOT NULL ENABLE,
"COLUMN2" NUMBER(4,0) NOT NULL ENABLE
)
/
CREATE UNIQUE INDEX "AID_PK" ON "TABLE_A" ("ID")
/
ALTER TABLE "TABLE_A" ADD CONSTRAINT "AID_PK" PRIMARY KEY ("ID")
USING INDEX "AID_PK" ENABLE
/
create or replace TRIGGER my_trigger
BEFORE INSERT OR UPDATE OR DELETE ON TABLE_A
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO TABLE_B(
ID,
COLUMN1,
COLUMN2)
VALUES(
:new.ID,
:new.COLUMN1,
:new.COLUMN2);
END IF;
END;
/
ALTER TRIGGER "my_trigger" ENABLE
/
CREATE SEQUENCE "MY_SEQ" MINVALUE 1 MAXVALUE 999999999999999 INCREMENT BY 1 START WITH 5002 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE GLOBAL;
/
CREATE OR REPLACE EDITIONABLE TRIGGER "MYSEQ_SEQ_IOT"
before insert on table_a
for each row
begin
select MY_SEQ.nextval into :new.id from dual;
end;
/
ALTER TRIGGER "MYSEQ_SEQ_IOT" ENABLE
/
Now when I run this statement:
INSERT INTO PER_ART(
COLUMN1,
COLUMN2
)
VALUES(
1111111,
2222222);
I get this error:
ORA-01400: cannot insert NULL into ("TABLE_B"."ID")
ORA-06512: at "my_trigger", line 7
ORA-04088: error during execution of trigger 'my_trigger'
Why is the ID null when the sequence should be populating it?
The order in which your two triggers fire is indeterminate. In my opinion, the best solution would be to just use one trigger:
create or replace TRIGGER my_trigger
BEFORE INSERT ON TABLE_A
FOR EACH ROW
BEGIN
select MY_SEQ.nextval
into :new.id
from dual;
INSERT INTO TABLE_B(
ID,
COLUMN1,
COLUMN2)
VALUES(
:new.ID, -- Or use MY_SEQ.curreval
:new.COLUMN1,
:new.COLUMN2);
END;
If you must have two triggers for some reason, then you can control their firing order using the FOLLOWS and PRECEDES clauses of the CREATE TRIGGER statement. Refer to the documentation for details on controlling trigger order.

Create Table / Sequence / Trigger in Apex Oracle SQL - ORA-00922 / ORA-00907 / ORA-00922

Using: Application Express 18.1.0.00.45
Please note: I am very new to Oracle Apex and SQL.
For a project I have to create an Application straight in Apex.
I was trying to create a table that works with a Primary Key that auto-increments itself.
Yesterday I created my first Application with a page for user input in a table, a page with table display and filter option and was playing around with forms, dashboard and authentication methods.
I removed the app after playing to start the "Real Work", but I my enthusiasm went quickly away when I realized that I am doing something very wrong but am not sure what.. :)
After lots of googling / reading etc, I am still not sure what is wrong..
See below the code:
-- Create Sequence
CREATE SEQUENCE seq_odm_for_pk
START WITH 1
INCREMENT BY 1
CACHE 100;
-- Create Table for User Input
CREATE TABLE ODM_Progress_v1 (
-- General Details:
ID int NOT NULL AUTO_INCREMENT,
TRAINEE varchar(50) NOT NULL, --1
COACH varchar(50) NOT NULL, --2
STATUS varchar(50) NOT NULL, --3
REGION varchar(5) NOT NULL, --4
-- Actions:
ACTION_TAKEN varchar(100) NOT NULL, --5
ACTION_DETAILS varchar(250), --6
ACTIONED_BY varchar(50) NOT NULL, --7
ACTIONED_DATE DATE NOT NULL, --8
-- Constraints that perform checks for each column:
CONSTRAINT CHK_GeneralDetails CHECK (TRAINEE!=COACH AND (STATUS IN('New', 'In Progress', 'Completed')) AND (REGION IN('EMEA', 'APAC', 'AMER'))),
-- Set Primary Key (Trainee+Coach):
CONSTRAINT PK_ODMProgress PRIMARY KEY (TRAINEE,REGION,ID)
);
-- Create Trigger
CREATE trigger_for_pk_odm_progress
BEFORE INSERT ON ODM_Progress_v1
FOR EACH ROW
WHEN (new.ID is null)
BEGIN
select seq_odm_for_pk.nextval into :new.ID from DUAL;
-- :new.PK_ODMProgress := seq_odm_for_pk.nextval;
END;
The script finishes running with 3 errors, see below:
CREATE OR REPLACE SEQUENCE seq_odm_for_pk START WITH 1
INCREMENT BY 1 CACHE 100
ORA-00922: missing or invalid option
CREATE TABLE ODM_Progress_v1 ( -- General Details: ID int NOT
NULL AUTO_INCREMENT, TRAINEE varchar(50) NOT NULL, --1 COACH
varchar(50) NOT NULL, --2 STATUS varchar(50) NOT NULL, --3
REGION varchar(5) NOT NULL, --4 -- Actions: ACTION_TAKEN
varchar(100) NOT NULL, --5 ACTION_DETAILS varchar(250), --6
ACTIONED_BY varchar(50) NOT NULL, --7 ACTIONED_DATE DATE NOT NULL,
--8 -- Constraints that perform checks for each column: CONSTRAINT CHK_GeneralDetails CHECK (TRAINEE!=COACH AND (STATUS
IN('New', 'In Progress', 'Completed')) AND (REGION IN('EMEA', 'APAC',
'AMER'))), -- Set Primary Key (Trainee+Coach): CONSTRAINT
PK_ODMProgress PRIMARY KEY (TRAINEE,REGION,ID) )
ORA-00907: missing right parenthesis
CREATE OR REPLACE trigger_for_pk_odm_progress BEFORE INSERT ON
ODM_Progress_v1 FOR EACH ROW WHEN (new.ID is null) BEGIN SELECT
seq_odm_for_pk.nextval INTO :new.ID FROM DUAL; --
:new.PK_ODMProgress := seq_odm_for_pk.nextval; END;
ORA-00922: missing or invalid option
Can you please help me unravel this (to me, complete) mystery?
The final application should at least contain 1 table with primary key and sequence (created from scratch, see above) and have at least 2 pages, one is for data input, the other is for data display with use tabs or navigation menu.
Thank you in advance!
That code looks OK, more or less. Here you go:
SQL> CREATE SEQUENCE seq_odm_for_pk
2 START WITH 1
3 INCREMENT BY 1
4 CACHE 100;
Sequence created.
Table: I'm on 11g which doesn't support auto-incremented columns, so I removed that clause:
SQL> CREATE TABLE ODM_Progress_v1 (
2 -- General Details:
3 ID int NOT NULL AUTO_INCREMENT,
4 TRAINEE varchar(50) NOT NULL, --1
5 COACH varchar(50) NOT NULL, --2
6 STATUS varchar(50) NOT NULL, --3
7 REGION varchar(5) NOT NULL, --4
8 -- Actions:
9 ACTION_TAKEN varchar(100) NOT NULL, --5
10 ACTION_DETAILS varchar(250), --6
11 ACTIONED_BY varchar(50) NOT NULL, --7
12 ACTIONED_DATE DATE NOT NULL, --8
13 -- Constraints that perform checks for each column:
14 CONSTRAINT CHK_GeneralDetails CHECK (TRAINEE!=COACH AND (STATUS IN('New', 'In Progress', 'Completed')) AND (REG
ION IN('EMEA', 'APAC', 'AMER'))),
15 -- Set Primary Key (Trainee+Coach):
16 CONSTRAINT PK_ODMProgress PRIMARY KEY (TRAINEE,REGION,ID)
17 );
ID int NOT NULL AUTO_INCREMENT,
*
ERROR at line 3:
ORA-00907: missing right parenthesis
SQL> l3
3* ID int NOT NULL AUTO_INCREMENT,
SQL> c/auto_increment//
3* ID int NOT NULL ,
SQL> /
Table created.
Trigger contains an error in line #1: it is not "trigger_for" but "trigger for" (no underscore):
SQL> CREATE trigger_for_pk_odm_progress
2 BEFORE INSERT ON ODM_Progress_v1
3 FOR EACH ROW
4 WHEN (new.ID is null)
5 BEGIN
6 select seq_odm_for_pk.nextval into :new.ID from DUAL;
7 -- :new.PK_ODMProgress := seq_odm_for_pk.nextval;
8 END;
9 /
CREATE trigger_for_pk_odm_progress
*
ERROR at line 1:
ORA-00901: invalid CREATE command
SQL> l1
1* CREATE trigger_for_pk_odm_progress
SQL> c/er_/er /
1* CREATE trigger for_pk_odm_progress
SQL> l
1 CREATE trigger for_pk_odm_progress
2 BEFORE INSERT ON ODM_Progress_v1
3 FOR EACH ROW
4 WHEN (new.ID is null)
5 BEGIN
6 select seq_odm_for_pk.nextval into :new.ID from DUAL;
7 -- :new.PK_ODMProgress := seq_odm_for_pk.nextval;
8* END;
SQL> /
Trigger created.
SQL>
So:
sequence is OK, but - for vast majority of cases - a simple create sequence seq_odm_for_pk; is enough
for CREATE TABLE remove AUTO_INCREMENT (if you aren't on 12c)
trigger: remove underscore
Now, depending on where you executed those commands, you might have got errors. If you ran them in Apex SQL Workshop, run them one-by-one (and keep only one command in the window). Doing so, it should be OK.
Also, I've noticed that you used VARCHAR datatype - switch to VARCHAR2.
Finally, there's no use in constraining primary key columns with the NOT NULL clause - primary key will enforce it by default.
As of Apex itself: the way you described it, you should create an Interactive Report; the Wizard will create a report (to view data), along with a form (to insert/modify/delete data).
The query you ran in your script is not the same as you posted in your code, as can be read in error text.
Code for creating your sequence as you wrote it in your code should be fine:
CREATE SEQUENCE seq_odm_for_pk
START WITH 1
INCREMENT BY 1
CACHE 100;
As of 11g you cannot use AUTO_INCREMENT in Oracle when creating table. It is not even necessary since you're having a trigger populating your :new.ID with nextval from sequence. So, in your CREATE TABLE remove AUTO_INCREMENT for your ID and everything should be fine.
While creating a trigger you omitted TRIGGER keyword (CREATE OR REPLACE TRIGGER trigger_for_pk_odm_progress).
Also, I'm not sure if you did or did not put END; at the end of your create trigger command. if not, put it.
I hope that helped :)

How to create SEQUENCE for GLOBAL TEMPORARY TABLE in oracle?

For example
CREATE GLOBAL TEMPORARY TABLE GGT_temp_reversal
(
sessionid VARCHAR (50) NULL,
syspk NUMERIC (23)
)
ON COMMIT DELETE ROWS ;
CREATE SEQUENCE GGT_temp_reversal_seq;
CREATE OR REPLACE TRIGGER GGT_temp_reversal_bir
BEFORE INSERT ON GGT_temp_reversal
FOR EACH ROW
WHEN (new.id IS NULL)
BEGIN
:new.id := GGT_temp_reversal_seq.NEXTVAL;
END;
Getting error "%s: invalid identifier"
You are creating trigger for an ID column
:new.id := GGT_temp_reversal_seq.NEXTVAL;
But you haven't declared it in CREATE TABLE
CREATE GLOBAL TEMPORARY TABLE GGT_TEMP_REVERSAL (
SESSIONID VARCHAR(50) NULL,
SYSPK NUMERIC(23)
)
Add an ID column and it will be fine

generated by default as identity for varchar data type in sql

I have a table xx_abc with data existing in the database.
I want to add a column confi_name in this table which is mandatory column.
If i add this column like
ALTER TABLE xx_abc
ADD
( confi_NAME VARCHAR2(2000) NOT NULL);
I am getting an error :
Error report:
SQL Error: ORA-01758: table must be empty to add mandatory (NOT NULL) column
01758. 00000 - "table must be empty to add mandatory (NOT NULL) column"
So I converted it to
ALTER TABLE xx_abc
ADD
( confi_name VARCHAR2(2000) generated by default as identity (START WITH 2, INCREMENT BY 1)
But this is also throwing an error because generated by defaut has to be of int data type. I basically want to make config_name with value which is unique for each row. and i cannot change its data type as well. Any work around ?
First add the column as nullable.
Then update that column with a default value in every row.
Then set the column to be NOT NULL.
As you have mentioned, the table had their values already. If you are going to add another column with "not null" property, make sure that you insert values equal to the number of values(rows) of the previous columns since you had set it to "not null" as its properties. Another way is not to use "not null" first then set the property to "not null" once you have enough values for the column already.
you have to set a default value for the existing rows before adding the constraint.
1)Modify the table
ALTER TABLE xx_abc
ADD
( confi_NAME VARCHAR2(2000));
2)Set default values
update XX_ABC set confi_NAME = 'DEFAULT';
COMMIT;
3)Add the constraint
alter table XX_ABC add check (confi_NAME is not null);
Existing table:
SQL> CREATE TABLE t(A VARCHAR2(10));
Table created.
SQL> INSERT INTO t VALUES('a');
1 row created.
SQL> INSERT INTO t VALUES('b');
1 row created.
SQL> INSERT INTO t VALUES('c');
1 row created.
SQL> COMMIT;
Commit complete.
Add a new column:
SQL> ALTER TABLE t ADD (b VARCHAR2(10));
Table altered.
Update the rows:
SQL> UPDATE t SET b = 'newvalue';
3 rows updated.
Add NOT NULL constraint:
SQL> ALTER TABLE t MODIFY b NOT NULL;
Table altered.
SQL> desc t
Name Null? Type
----------------------------------------- -------- -------------
A VARCHAR2(10)
B NOT NULL VARCHAR2(10)
SQL>

SQLPlus AUTO_INCREMENT Error

When I try and run the following command in SQLPlus:
CREATE TABLE Hotel
(hotelNo NUMBER(4) NOT NULL AUTO_INCREMENT,
hotelName VARCHAR(20) NOT NULL,
city VARCHAR(50) NOT NULL,
CONSTRAINT hotelNo_pk PRIMARY KEY (hotelNo));
I get the following error:
(hotelNo NUMBER(4) NOT NULL AUTO_INCREMENT,
*
ERROR at line 2:
ORA-00907: missing right parenthesis
What am I doing wrong?
Many will gripe about this not being a standard feature in Oracle, but when it’s as easy as two more commands after your CREATE TABLE command I can’t see any good reason to use fancy SQL on every insert.
First let’s create a simple table to play with.
SQL> CREATE TABLE test
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
Table created.
Now we’ll assume we want ID to be an auto increment field. First we need a sequence to grab values from.
SQL> CREATE SEQUENCE test_sequence
START WITH 1
INCREMENT BY 1;
Sequence created.
Now we can use that sequence in a BEFORE INSERT trigger on the table.
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT
ON test
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT test_sequence.nextval INTO :NEW.ID FROM dual;
END;
/
SQL> INSERT INTO test (name) VALUES ('Jon');
1 row created.
SQL> INSERT INTO test (name) VALUES (’Bork’);
1 row created.
SQL> INSERT INTO test (name) VALUES (’Matt’);
1 row created.
SQL> SELECT * FROM test;
ID NAME
———- ——————————
1 Jon
2 Bork
3 Matt
Oracle has no auto_increment, you need to use sequences.
Or - starting with Oracle 12.1 - you can simply have:
CREATE TABLE employee
(
id NUMBER GENERATED by default on null as IDENTITY
....
)