oracle verify insert then delete dynamic tables - sql

Is there any way i can verify if my inserts were successful into my secondary table and then deleting from my original table those rows, without using a trigger.
SO i have this query: has 2 dynamic tables n_tab and n_tab2
testes:= 'INSERT all into ' || n_tab2 || ' SELECT * FROM ' || n_tab || ' where criado_em< ' || SYSDATE;
EXECUTE IMMEDIATE testes;
after this insert i would like to verify if all the rows were inserted and after that
stmt_del:= 'DELETE FROM ' || n_tab || ' WHERE EXISTS (SELECT 1
FROM ' || n_tab2 || ' WHERE ' 'need to find a way to associate the pk and fk dinamically'
EXECUTE IMMEDIATE testes;
Thank you in advance.

if not find any way , here is way using SQL%ROWCOUNT
DECLARE
stmt varchar2(100);
mycolumn NUMBER := 100 ;
BEGIN
stmt := 'insert into mytable values('||mycolumn||')';
execute immediate stmt;
dbms_output.put_line('value '||SQL%ROWCOUNT);
IF SQL%ROWCOUNT > 1 THEN
stmt_del:= 'delete from mytable where condition';
EXECUTE IMMEDIATE testes;
END IF;
END;

Related

PLSQL procedure for automatic column type changing

Let's assume following table:
drop table test1;
create table test1(
A number(10)
);
insert into test1 values (1);
insert into test1 values (10);
So as you can see table TEST1 is already populated. What i need to do is to change types of column A to varchar2. Since this column has values we can't just use following code:
alter table test1 modify A varchar2(10);
So i have wrote stored procedure which:
Renames column A to A1 ->
Then adds new column called A of type varchar2 ->
Then updates column A with values from column A1 ->
And ultimately drops old column A1.
Code which runs this process is following:
create or replace procedure change_col_type_to_varchar2(p_tab in varchar2, p_col in varchar2)
is
v_string clob;
cursor cur is
select column_name
from all_tab_columns
where table_name = upper(p_tab) and
column_name in (select regexp_substr(p_col,'[^,]+', 1, level) from dual
connect by regexp_substr(p_col, '[^,]+', 1, level) is not null);
begin
for i in cur loop
v_string := 'alter table ' || p_tab || ' rename column ' || i.column_name || ' to ' || i.column_name || '1' || ';';
dbms_lob.append(v_string,''||chr(10)||'');
dbms_lob.append(v_string, 'alter table ' || p_tab || ' add ' || i.column_name || ' varchar2(10);');
dbms_lob.append(v_string,''||chr(10)||'');
dbms_lob.append(v_string, 'update ' || p_tab || ' set ' || i.column_name || ' = ' || i.column_name || '1' || ';');
dbms_lob.append(v_string,''||chr(10)||'');
dbms_lob.append(v_string, 'alter table ' || p_tab || ' drop column ' || i.column_name || '1' || ';');
EXECUTE IMMEDIATE v_string;
DBMS_OUTPUT.PUT_LINE(v_string);
v_string := NULL;
end loop;
end;
I'am trying to apply this procedure to TEST1:
begin
change_col_type_to_varchar2('TEST1', 'A');
end;
And get error:
Error report -
ORA-23290: This operation may not be combined with any other operation
ORA-06512: at "YAVORSKYIY_DM.CHANGE_COL_TYPE_TO_VARCHAR2", line 19
ORA-06512: at "YAVORSKYIY_DM.CHANGE_COL_TYPE_TO_VARCHAR2", line 19
ORA-06512: at line 2
23290. 00000 - "This operation may not be combined with any other operation"
*Cause: ALTER TABLE RENAME COLUMN/CONSTRAINT operation was given in
conjunction with another ALTER TBALE Operation. This is not
allowed.
*Action: Ensure that RENAME COLUMN/CONSTRAINT is the only operation
specified in the ALTER TABLE.
But just typing :
alter table test1 rename column A to A1;
alter table test1 add A varchar2(100);
update test1 set A = A1;
alter table test1 drop column A1;
Works perfect.
Does anybody have any ideas about how to overcome this problem?
Appreciate your help.
the below will do what you asked for.
declare
procedure change_col_type_to_varchar2(p_tab in varchar2, p_col in varchar2)
is
v_string clob;
cursor cur is
select column_name
from all_tab_columns
where table_name = upper(p_tab) and
column_name in (select regexp_substr(p_col,'[^,]+', 1, level)
from dual
connect by regexp_substr(p_col, '[^,]+', 1, level) is not null);
begin
for i in cur loop
v_string := 'alter table ' || p_tab || ' rename column ' || i.column_name || ' to ' || i.column_name || '1';
execute immediate v_string;
v_string := 'alter table ' || p_tab || ' add ' || i.column_name || ' varchar2(10)';
execute immediate v_string;
v_string := 'update ' || p_tab || ' set ' || i.column_name || ' = ' || i.column_name || '1' ;
execute immediate v_string;
v_string := 'alter table ' || p_tab || ' drop column ' || i.column_name || '1' ;
execute immediate v_string;
v_string := NULL;
end loop;
end;
begin
DBMS_OUTPUT.PUT_LINE('Before calling');
change_col_type_to_varchar2('TEST1','A');
DBMS_OUTPUT.PUT_LINE('After calling');
end;
Well, execute each statement alone, instead of concatenating them. And you don't need LOBs, varchar2 for each one should be enough.
I propose other algorithm.
create new table 'table2' with varchar column;
select all values from table1.A and insert to table2 with to_char() conversion;
drop table1;
rename table2 to table1;
profit!

Oracle procedure to delete records in all tables of an owner

I am trying to create an Oracle procedure to delete records from multiple tables of an owner based upon a distinct count condition:
Firstly I am trying to obtain the tables for which I want to delete those records with this query:
SELECT * FROM ALL_TABLES WHERE OWNER = 'Lorik' AND TABLE_NAME LIKE 'UT_%';
This results in a total of 300 tables, now all of those tables have a column named: DATE_INC
I am trying to delete records from all of the tables if this COUNT(DISTINCT DATE_INC) > 5.
Assuming that one of those 300 tables is named UT_NAMES:
SELECT COUNT(DISTINCT DATE_INC) FROM Lorik.UT_NAMES;
So if the count exceeds 5, then I want to delete the records with the minimum date:
DELETE MIN(DATE_INC) FROM Lorik.UT_NAMES;
Can someone please link these steps together so I can loop through each table of that owner and obtain the distinct date count and delete records based upon the above cited condition.
Thanks in advance!
You can use 'EXECUTE IMMEDIATE' in PL/SQL to accomplish your goal:
DECLARE
strTable VARCHAR2(32767);
nCount NUMBER;
BEGIN
FOR aRow IN (SELECT *
FROM ALL_TABLES
WHERE OWNER = 'Lorik' AND
TABLE_NAME LIKE 'UT_%')
LOOP
strTable := aRow.OWNER || '.' || aRow.TABLE_NAME;
EXECUTE IMMEDIATE 'SELECT COUNT(DISTINCT DATE_INC) FROM ' || strTable
INTO nCount;
IF nCount > 5 THEN
EXECUTE IMMEDIATE 'DELETE FROM ' || strTable ||
' WHERE DATE_INC = (SELECT MIN(DATE_INC) ' ||
'FROM ' || strTable || ')';
END IF;
END LOOP;
END;
Not tested on animals - you'll be first! :-)
As pointed out by #Andrew this seems to be very basic processes.
Declare some variables.
Open a cursor.
Use dynamic sql to count
Use dynamic sql to delete
Add some log information
_
declare
v_cnt number;
v_sql varchar2(1000);
begin
for cur in (SELECT * FROM ALL_TABLES WHERE OWNER = 'HR' AND TABLE_NAME LIKE 'E%')
loop
v_sql := 'select count(distinct department_id||''date_inc'') from '||cur.owner||'. '||cur.table_name;
execute immediate v_sql into v_cnt;
dbms_output.put_line (cur.table_name || ': ' || v_cnt);
if v_cnt > 5 then
v_sql := 'delete from '||cur.owner||'. '||cur.table_name || ' where date_inc = (select min (date_inc) from ' ||cur.owner||'. '||cur.table_name || ')';
dbms_output.put_line (v_sql);
-- execute immediate v_sql;
end if;
end loop;
rollback;
-- commit;
end;
A little bit simpler dynamic SQL for deleting rows, as it uses a local variable:
declare
l_cnt number; -- counter variable
l_min_date date; -- MIN(date_inc)
begin
for cur_t in (select table_name from all_tables
where owner = 'Lorik' -- are you sure it is not uppercase, LORIK?
and table_name like 'UT%' -- underline is wildcard character so you don't need it
)
loop
execute immediate 'select count(distinct date_inc), min(date_inc) from ' ||
cur_t.table_name into l_cnt, l_min_date;
if l_cnt > 5 then
execute immediate 'delete from ' || cur_t.table_name ||
' where date_inc = ' || l_min_date_inc;
end if;
end loop;
end;
/

00933. 00000 - "SQL command not properly ended" DYNAMIC SQL

DECLARE
CURSOR c_ddy (p_table_name VARCHAR2, p_table_name_2 VARCHAR2)
IS
(SELECT column_name
FROM ( SELECT column_name
FROM user_tab_columns
WHERE table_name = p_table_name
ORDER BY column_name));
TYPE t_content IS TABLE OF VARCHAR2 (9000)
INDEX BY BINARY_INTEGER;
a_content t_content;
l_sql VARCHAR2 (1000);
BEGIN
FOR r_ddy IN c_ddy ('TABLE_a', 'TABLE_B')
LOOP
l_sql :=
'SELECT '
|| r_ddy.column_name
|| ' FROM TABLE_A '
|| 'MINUS'
|| 'SELECT '
|| r_ddy.column_name
|| 'FROM TABLE_B';
EXECUTE IMMEDIATE l_sql BULK COLLECT INTO a_content;
DBMS_OUTPUT.put_line (l_sql);
END LOOP;
END;
Trying to output every column in TABLE_A minus every column in TABLE_B.
A space is missing in the SQL string.
Try this:
l_sql :=
'SELECT '
|| r_ddy.column_name
|| ' FROM TABLE_A '
|| ' MINUS '
|| ' SELECT '
|| r_ddy.column_name
|| ' FROM TABLE_B';
UPD: For some reason the spaces were gone before. Now I put them again.

Runtime Query in Oracle store procedures not returning proper result

This is first my stint with procedure and I am trying to execute below oracle procedure but facing some issue. Any inputs on this would be really helpful:
Issue:-----
I have a select query that returns two values:
src_Columns contains:
ID_ELEMENT
ID_ELEMENT_SA
Now, When I am trying to travesre a select-query(single column) result using "For Loop", I am not getting the values of the column rather I am getting its name only.
FOR columnItem IN (SELECT src_Columns FROM ELEM90_LNK_ELEM_BOSE)
LOOP
dbms_output.put_line('src_Columns 3: ' || columnItem.src_Columns);
query_test:= 'insert into ' || destination_Table || '(NAME,' || dest_Columns_Value || ') VALUES( ''' || src_name_Value || ''',''' || columnItem.dummyValue || ''')';
dbms_output.put_line('query_test:' || query_test);
execute immediate query_test;
END LOOP;
I mean the test query generated is following when i use variable name(src_columns):
insert into ATT_WTPART(NAME,STRINGVALUE) VALUES( 'ID_ELEMENT_SA','ID_ELEMENT_SA')
whereas if I use ID_ELEMENT_SA instead of src_Columns in FOR LOOP
FOR columnItem IN (SELECT ID_ELEMENT FROM ELEM90_LNK_ELEM_BOSE)
then I get proper values that are desired like
insert into ATT_WTPART(NAME,STRINGVALUE) VALUES( 'ID_ELEMENT_SA','ID05')
How can I make sure that I get the values even when I am using the variable name instead of any hard-coding
Below is the Complete Procedure:-------------
create or replace
PROCEDURE ELEM90_Lnk_Elem_ATT_WTPART_MK
AS
CURSOR targ_dest_relation IS
SELECT sourcecolumn FROM mapping where destinationtable='ATT_WTPART';
BEGIN
DECLARE
dest_Columns varchar2(1000);
src_Columns varchar2(1000);
src_Type varchar2(1000);
destination_Table varchar2(1000) := 'ATT_WTPART';
source_Table varchar2(1000) := 'ELEM90_LNK_ELEM_BOSE';
query_test varchar2(1000);
query_test2 varchar2(1000);
src_name varchar2(255);
src_Type_Value varchar2(255);
dest_Columns_Value varchar2(255);
src_name_Value varchar2(255);
for_query varchar2(1000);
for_query_data varchar2(1000);
dummyValue varchar2(1000);
BEGIN
FOR rec IN targ_dest_relation loop
dbms_output.put_line('destination_Table: ' || destination_Table);
dbms_output.put_line('source_Table: ' || source_Table);
src_Columns := rec.sourcecolumn;
dbms_output.put_line('src_Columns: ' || src_Columns);
src_Type := 'select data_type from user_tab_columns where table_name ='''||source_Table||'''and column_name='''|| src_Columns ||'''';
dbms_output.put_line('src_Type: ' || src_Type);
execute immediate src_Type INTO src_Type_Value;
dbms_output.put_line('src_Type_Value: ' || src_Type_Value);
dest_Columns := 'select DEST_COLUMN from ATT_PART_MAPPING where SOURCETYPE='''|| src_Type_Value || '''';
dbms_output.put_line('dest_Columns: ' || dest_Columns);
execute immediate dest_Columns INTO dest_Columns_Value;
dbms_output.put_line('dest_Columns_Value: ' || dest_Columns_Value);
src_name := 'select column_name from user_tab_columns where table_name ='''|| source_Table ||''' and column_name= ''' || src_Columns || '''';
dbms_output.put_line('src_name: ' || src_name);
execute immediate src_name INTO src_name_Value;
dbms_output.put_line('src_name_Value: ' || src_name_Value);
FOR columnItem IN (SELECT src_Columns FROM ELEM90_LNK_ELEM_BOSE)
LOOP
dbms_output.put_line('src_Columns 3: ' || columnItem.src_Columns);
query_test:= 'insert into ' || destination_Table || '(NAME,' || dest_Columns_Value || ') VALUES( ''' || src_name_Value || ''',''' || columnItem.dummyValue || ''')';
dbms_output.put_line('query_test:' || query_test);
execute immediate query_test;
END LOOP;
END loop;
END;
END;
The problem with the line
FOR columnItem IN (SELECT src_Columns FROM ELEM90_LNK_ELEM_BOSE)
is that src_Columns is a local variable. As a result, you end up selecting the same value for each row in ELEM90_LNK_ELEM_BOSE.
If you want the value of the local variable to be used as a column name in the query, you must use dynamic SQL instead. Try replacing FOR columnItem ... LOOP ... END LOOP with the following:
OPEN curs FOR 'SELECT ' || src_Columns || ' FROM ELEM90_LNK_ELEM_BOSE';
LOOP
FETCH curs INTO column_value;
EXIT WHEN curs%NOTFOUND;
dbms_output.put_line('src_Columns 3: ' || column_value);
query_test:= 'insert into ' || destination_Table || '(NAME,' || dest_Columns_Value || ') VALUES( ''' || src_name_Value || ''',''' || column_value || ''')';
dbms_output.put_line('query_test:' || query_test);
execute immediate query_test;
END LOOP;
CLOSE curs;
You will need to declare the following extra variables:
curs SYS_REFCURSOR;
column_value VARCHAR2(4000);
However, in truth it would probably be better to remove the loop entirely. You can replace it with an INSERT INTO ... SELECT ... FROM ... statement instead, such as the following:
EXECUTE IMMEDIATE 'INSERT INTO ' || destination_Table || ' (NAME,' ||
dest_Columns_Value || ') SELECT :name,' || src_Columns ||
' FROM ELEM90_LNK_ELEM_BOSE' USING src_name_Value;
This also gets rid of the need for the two local variables curs and column_value, and is also likely to be considerably faster, as there's no need to parse dynamic SQL once for each row in the destination table.
Is it working better if you try this one:
query_test:= 'insert into ' || destination_Table ||
'(NAME,'||dest_Columns_Value||') VALUES (:p1, :p2)';
execute immediate query_test USING src_name_Value, columnItem.dummyValue;
At least it should have a positive impact on performance.

query each column of a table in a loop - Oracle Database

I'm working with an oracle database and what I basically need to do is to count the number of NULL fields per column in a certain table.
something like that:
DECLARE
BlankCount number(20);
i number(2) := 1;
BEGIN
loop that would take each column individualy and exit after the last one
SELECT COUNT(*) INTO BlankCount FROM name_of_my_table
DBMS_OUTPUT.PUT_LINE('Column '||i||' has '||BlankCount||' empty cells');
i := i + 1;
END LOOP;
END;
I just couldn't find anything that would do the loop part.
It would also be nice if instead of just numbering them (with the i) I could display the column name (but that is not very important).
Thank you!
Something like this:
declare
mytable varchar(32) := 'MY_TABLE';
cursor s1 (mytable varchar2) is
select column_name
from user_tab_columns
where table_name = mytable
and nullable = 'Y';
mycolumn varchar2(32);
query_str varchar2(100);
mycount number;
begin
open s1 (mytable);
loop
fetch s1 into mycolumn;
exit when s1%NOTFOUND;
query_str := 'select count(*) from ' || mytable || ' where ' || mycolumn || ' is null';
execute immediate query_str into mycount;
dbms_output.put_line('Column ' || mycolumn || ' has ' || mycount || ' null values');
end loop;
end;
Try using cursor approach and Dynamic SQL as mentioned in this thread: How to loop through columns in an oracle pl/sql cursor
HTH.