oracle reentrant alter table - sql

I have an SQL script to execute multiple times (must be reentrant).
One of the script line is
alter table MATABLE modify (MADATA null);
This commands works well when the 'not null' constraint for column MADATA of table MATABLE is effectively removed. But the second time, I got an error, example:
Erreur SQL : ORA-01451: colonne à modifier en non renseignée (NULL) ne peut être passée à NULL
01451. 00000 - "column to be modified to NULL cannot be modified to NULL"
That's because the constraint was already removed by the first execution and no more exist.
How to execute this same script without error ?
maybe through PL/SQL Script ?

You can use the data dictionary view user_tab_cols to check the table before doing the update.
declare
lCount number;
begin
select count(*) into lCount from user_tab_cols
where table_name = 'MATABLE'
and column_name = 'MADATA'
and nullable = 'N';
if (lCount = 1) then
execute immediate 'alter table MATABLE modify (MADATA null)';
end if;
end;
Note that user_tab_cols only contains the information about tables in the same schema as the logged on user. If you are modifying tables of another user, you can user all_tab_cols or dba_tab_cols.
Another option would be to use an exception handler and just throw away the exception, like this:
begin
execute immediate 'alter table MATABLE modify (MADATA null)';
exception
when others then
null;
end;

It is normal behavior.
It can happen in two scenarios :
1) If your field column is a constraint
2) if you've already defined the field column as allowing NULL values.

Related

Postgresql query not able to add column where the column name is similar to an SQL keyword?

I have an list of internal names for different columns I need to add, and one is named end which causes an issue since this is an sql keyword.
DO
$$
BEGIN
IF NOT EXISTS (SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = lower('entity')
AND column_name = lower('end')
) THEN
ALTER TABLE public.entity
ADD COLUMN "end" TEXT NULL;
ELSE
ALTER TABLE public.entity
ALTER COLUMN "end" TYPE TEXT;
END IF;
END
$$;
I seem to have read some posts where the end keyword can be used as a column if it qouted,
but this still fails?
The error message i get is :
MessageText: syntax error at or near "end"
Why?

Executing a PostgreSQL query with an EXCEPTION results in two different ERROR messages

I have an PostgreSQL query that includes a transaction and an exception if a column is duplicated:
BEGIN;
ALTER TABLE "public"."cars"
ADD COLUMN "top_speed" text;
EXCEPTION WHEN duplicate_column THEN NOTHING;
ROLLBACK;
In this query I am trying to add a column that already exists (playing a little bit with exceptions) and if it does then the query shall just ignore it. At the moment I am not really sure if the exception-code I am using is the right (couldn't find a site where they are described; only found this)
My Problem is if I execute this query I get the error-message:
ERROR: column "top_speed" of relation "cars" already exists
And if I execute it a second time the error-message changes to:
ERROR: current transaction is aborted, commands ignored until end of transaction block
Try an anonymous code block. As Laurenz mentioned, you were mixing PL/pgSQL and SQL commands.
Sample table
CREATE TABLE t (f1 TEXT);
Anonymous code block
DO $$
BEGIN
IF (SELECT count(column_name) FROM information_schema.columns
WHERE table_schema = 'public' AND
table_name = 't' AND
column_name = 'f2') = 0 THEN
ALTER TABLE public.t ADD COLUMN "f2" text;
END IF;
END$$;
After execution you have your new column. If the column already exists, it will do nothing.
SELECT * FROM t;
f1 | f2
----+----
0 Zeilen
In PostgreSQL 9.6+ you can use IF NOT EXISTS to check if a given column already exists in the table before creating it:
ALTER TABLE t ADD COLUMN IF NOT EXISTS f2 TEXT;
Code at db<>fiddle

Oracle SQL commands that work when executed separately does not work when executed together. Why?

This is regarding a migration script. The required migration can be done by using 4 separate SQL commands. However, when they are combined to run as a script I am getting PLS-00103: Encountered the symbol error.
These are the SQL commands that I've used to do the migration. The table will have a PK which is a composite key of 3 columns in the table. First I need to remove the constraint, then add a new column called ID to that table, make it auto incremental by adding a sequence and then make it the new PK of the table.
Following commands work and does the exact job when I execute them one by one.
BEGIN
FOR item IN (
SELECT *
FROM all_constraints
WHERE table_name = 'TEST_DB_CHANGE'
)
LOOP
EXECUTE immediate 'ALTER TABLE TEST_DB_CHANGE DROP CONSTRAINT ' || item.CONSTRAINT_NAME;
END LOOP;
END;
/
BEGIN
EXECUTE IMMEDIATE 'CREATE SEQUENCE TEST_DB_CHANGE_SEQUENCE START WITH 1 INCREMENT BY 1 nomaxvalue';
END;
/
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD (ID NUMBER DEFAULT TEST_DB_CHANGE_SEQUENCE.nextval)';
END;
/
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD CONSTRAINT TEST_DB_CHANGE_PK PRIMARY KEY (ID)';
END;
But when they are executed together I get the following error.
*Query execution failed
Reason:
SQL Error [6550] [65000]: ORA-06550: line 11, column 1:
PLS-00103: Encountered the symbol "/" *
I tried removing the "/" from that line, from every line, from every line except the last line, but none of that fixed the issue. Then the error will change to:
Reason:
SQL Error [6550] [65000]: ORA-06550: line 12, column 1:
PLS-00103: Encountered the symbol "BEGIN"
What am I doing wrong here?
I don't know how you have combined them but it should be:
BEGIN
FOR item IN (
SELECT *
FROM all_constraints
WHERE table_name = 'TEST_DB_CHANGE'
)
LOOP
EXECUTE immediate 'ALTER TABLE TEST_DB_CHANGE DROP CONSTRAINT ' || item.CONSTRAINT_NAME;
END LOOP;
EXECUTE IMMEDIATE 'CREATE SEQUENCE TEST_DB_CHANGE_SEQUENCE START WITH 1 INCREMENT BY 1 nomaxvalue';
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD (ID NUMBER DEFAULT TEST_DB_CHANGE_SEQUENCE.nextval)';
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD CONSTRAINT TEST_DB_CHANGE_PK PRIMARY KEY (ID)';
END;

not able to drop and recreate the oracle text index

I am not able to drop and recreate the oracle text index.
SQL> drop index "WBR"."CTX_t1";
Index dropped
SQL>
SQL> CREATE INDEX "WBR"."CTX_t1"
2 ON WBR.t1(ASSET_XML)
3 INDEXTYPE IS "CTXSYS"."CONTEXT"
4 PARAMETERS ('DATASTORE CTXSYS.DIRECT_DATASTORE SECTION GROUP CTXSYS.AUTO_SECTION_GROUP SYNC (every "SYSDATE+10/1440")')
5 ;
CREATE INDEX "WBR"."CTX_t1"
ON WBR.t1(ASSET_XML)
INDEXTYPE IS "CTXSYS"."CONTEXT"
PARAMETERS ('DATASTORE CTXSYS.DIRECT_DATASTORE SECTION GROUP CTXSYS.AUTO_SECTION_GROUP SYNC(every "SYSDATE+10/1440")')
ORA-29855: error occurred in the execution of ODCIINDEXCREATE routine
ORA-20000: Oracle Text error:
DRG-10507: duplicate index name: CTX_t1
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.TEXTINDEXMETHODS", line 366
Even after dropping the cintext index, I can see the entry in CTXSYS.CTX_INDEXES.
The job and internal tables are still there in database:
DR$CTX_t1$I
DR$CTX_t1$J--job
DR$CTX_t1$K
DR$CTX_t1$N
DR$CTX_t1$R
DR$CTX_t1$X
any suggestions?
1) check if there exists an other object with the same name (possible case insensitive)
select owner, object_name, object_type from dba_objects where upper(object_name) like '%CTX_T1%';
if yes drop it.
2) try drop the index with the FORCE option
drop index "WBR"."CTX_t1" FORCE;
if it doesn't help:
3) contact Oracle support
it seems a bug on oracle. We have a script who refresh our quality database from the production database. To solve this problem, we execute this PL/SQL script before refresh begin.
/**
* Correctif bug sur la suppression d'index full text:
* Unable to recreate an Oracle Text index as the database continually throws a "DRG-10507: duplicate index name" error
* http://ask4dba.blogspot.com/2016/11/drg-10507-in-creating-text-index-after.html
* https://www.ibm.com/support/pages/unable-recreate-oracle-text-index-database-continually-throws-drg-10507-duplicate-index-name-error
**/
DECLARE
LR$IDX_ID NUMBER(15);
LR$IDX_NAME VARCHAR2(255);
LR$SCHEMA VARCHAR2(255);
CURSOR C1 IS
select IDX_ID, IDX_NAME, usr.USERNAME from CTXSYS.DR$INDEX
join all_users usr on usr.USER_ID = IDX_OWNER#
where IDX_NAME in ('IDX_EDI_EMISSION_MSG_EAI', 'IDX_EDI_EMISSION_MSG', 'IDX_EDI_RECEPTION_MSG', 'IDX_EDI_RECEPTION_MSG_TMS');
BEGIN
DBMS_OUTPUT.put_line('DEBUT de la suppression des index fulltext' );
OPEN C1;
LOOP
FETCH C1 INTO LR$IDX_ID, LR$IDX_NAME, LR$SCHEMA;
EXIT WHEN C1%NOTFOUND;
BEGIN
BEGIN
DBMS_OUTPUT.put_line('Suppression (drop) de l''index '|| LR$SCHEMA || '.' || LR$IDX_NAME );
execute immediate 'DROP INDEX ' || LR$SCHEMA || '.' || LR$IDX_NAME;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('Erreur Oracle #'||TO_CHAR(SQLCODE)||' : '||SQLERRM(SQLCODE));
DBMS_OUTPUT.put_line('L''index ' || LR$IDX_NAME ||' n''existe pas : ' || LR$IDX_ID);
END;
DBMS_OUTPUT.put_line('Suppression des lignes de l''index ' || LR$IDX_ID);
delete from ctxsys.dr$index_value where IXV_IDX_ID = LR$IDX_ID;
delete from ctxsys.dr$index_object where IXO_IDX_ID = LR$IDX_ID;
delete from ctxsys.dr$index where idx_id = LR$IDX_ID;
commit;
END;
END LOOP;
CLOSE C1;
COMMIT;
End ;
/
[1] Oracle Text: Create Or Alter Index Fails With DRG-50857, ORA-27486 ( Doc ID 2497828.1 )
grant create job to the user and then try to create the indexes, it should work.
I had a situation of changing index sync parameter from ('SYNC (on commit)') to ('SYNC (EVERY "SYSDATE+15/1440")'), as this will automatically use a Oracle job, the schema should have create job privilege.
it's not an answer basically, for those who get a slightly different error (i'm on Oracle 12c) during create index and right after drop index statements:
ORA-29855: error occurred in the execution of ODCIINDEXCREATE routine
ORA-20000: Oracle Text error:
DRG-50857: oracle error in drvxtab.create_index_tables
ORA-00955: name is already used by an existing object
ORA-06512: at "CTXSYS.DRUE", line 171
ORA-06512: at "CTXSYS.TEXTINDEXMETHODS", line 316
there seems to be a time lag (or something else) between drop of the index, and the cleanup of the related data from the CTXSYS tables (but i didn't need any commit statements). so for me, executing drop of the index AGAIN and running the same create statement AGAIN resolved the issue (the second create runs OK)

Oracle: Modify primary/foreignkeys and constrains inside a TRIGGER

we have an issue with the folowing trigger where we have to disable certain constraints to add the primary key of a table:
create or replace trigger TRG_NAMENSAENDERUNG_MA
after update of vname, nname on mitarbeiter
referencing new as new old as old
for each row
declare
initialien char(2);
benutzernr int;
benutzername_neu char(5);
benutzername_alt char(5);
begin
/*...
Code sets corect values to all variables.
...*/
/* the following is suposed to disable the two constraints*/
for i in (select fk_session_log_ben_name, SESSION_LOGGING FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.session_logging||' DISABLE CONSTRAINT '||i.fk_session_log_ben_name||'';
end loop;
for i in (select fk_geraetekto_ben_name, GERAETEKONTO FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.geraetekonto||' DISABLE CONSTRAINT '||i.fk_geraetekto_ben_name||'';
end loop;
/*Update statements which can only work without the constraints!!: */
UPDATE BENUTZERKONTO SET BENUTZERNAME = benutzername_neu WHERE BENUTZERNAME = benutzername_alt;
UPDATE SESSION_LOGGING SET BENUTZERNAME = benutzername_neu WHERE BENUTZERNAME = benutzername_alt;
UPDATE GERAETEKONTO SET BENUTZERNAME = benutzername_neu WHERE BENUTZERNAME = benutzername_alt;
/*Supposed to re-enable the constraints. */
for i in (select fk_session_log_ben_name, SESSION_LOGGING FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.session_logging||' ENABLE CONSTRAINT '||i.fk_session_log_ben_name||'';
end loop;
for i in (select fk_geraetekto_ben_name, GERAETEKONTO FROM USER_CONSTRAINTS) loop
execute immediate 'ALTER TABLE'||i.geraetekonto||' ENABLE CONSTRAINT '||i.fk_geraetekto_ben_name||'';
end loop;
end TRG_NAMENSAENDERUNG_MA;
It throws the error that SESSION_LOGGING would be an "invalid identifier". It is typed right though and we copied the syntax from the example from the Oracale page.
What's the easiest way to achieve what we want?
Thanks in advance!
Here's the invalid identifier, these columns do not exist in USER_CONSTRAINTS. The full error message should have included the line number and given a hint at the meaning.
select fk_session_log_ben_name, SESSION_LOGGING FROM USER_CONSTRAINTS
The code should probably be this:
select constraint_name fk_session_log_ben_name, table_name SESSION_LOGGING
FROM USER_CONSTRAINTS;
My first suggestion is to redesign the schema so that it's no need to change the PK values (especially by users). PK must be surrogate. There must be serious reasons for a decision like yours. Hope you don't need such reasons :) The redesign mentioned, methinks, would be less expensive than struggling with the problem you cast. With changing PK values you'll probably face such problems again and again as the application is evolved.