Dynamically selecting table name using sub-query in from clause - oracle

I have a mapping table with source and table name as attributes.
And i have the below query :
select *
from
(select table_name from mapping_table where source='CL Table')
I want to retrieve the data of the table_name but this query will return only the table name not the data.
How to do it?

DECLARE
v_mystring VARCHAR(50);
v_my_ref_cursor sys_refcursor;
myrecord <some_table_or_type>;
BEGIN
select table_name into my_table_name
from mapping_table
where source='CL Table';
v_mystring := 'SELECT * from '||my_table_name;;
OPEN v_my_ref_cursor FOR v_mystring;
LOOP
FETCH v_my_ref_cursor INTO myrecord;
-- your processing
END LOOP;
CLOSE v_my_ref_cursor;
END;

Related

Create backup table concatenated with sysdate before deleting the rows in oracle procedure

I have created a package and defined a procedure to delete specific rows retrieved by the cursor.
Before the rows were deleted from the table, I want to take a backup of those records every time the package is compiled and I need the backup table to be created as tablename concatenated with sysdate.
ex: if table name is emp, backup table should be created as emp_2020_10_16
Below is the sample code I have created:
PROCEDURE DELETE_REC(
P_retcode NUMBER,
P_errorbuff VARCHAR2,
P_unit_id NUMBER,
P_join_date VARCHAR2
)
IS
CURSOR cur1
IS
SELECT unit_ID,dept_ID,join_DATE
FROM EMP MMT
WHERE MMT.dep_TYPE_ID IN (44,35)
AND MMT.unit_id = P_unit_id
AND MMT.join_date < to_date(P_join_date,'RRRR/MM/DD HH24:MI:SS');
BEGIN
--begin
-- EXECUTE IMMEDIATE 'Create table EMP_' || to_char(sysdate,'yyyy_mm_dd') || ' as select * from EMP MMT WHERE MMT.dep_TYPE_ID IN (44,35)
AND MMT.unit_id = P_unit_id
AND MMT.join_date < to_date(P_join_date,'RRRR/MM/DD HH24:MI:SS');
--
-- end;
/*Here i would like to create backup table like above before executing the below delete statement but i am not sure about the correct standards that i should be using for above dynamic statement*/
FOR val IN cur1
LOOP
DELETE
FROM EMP MMT
WHERE MMT.dept_ID= val.dept_id;
How can I backup the table using above dynamic statement in best possible way? I am still learning PL&SQL.
Maybe sth like this would help:
create table employees as select * from hr.employees;
--drop table emp_2020_10_18;
--drop table employees;
----------------
declare
vTabName varchar2(50);
nDept_id number := 10;
nCnt number := 0;
vSQL varchar2(1000);
begin
vTabName := 'emp_'||to_char(sysdate, 'yyyy_mm_dd');
-- check if table exists
begin
execute immediate 'select count(*) from emp_tmp' into nCnt;
exception when others then
nCnt := -1;
end;
-- if not exists create one
if nCnt = -1 then
execute immediate 'create table '|| vTabName||' as select * from employees where 1=2' ;
end if;
execute immediate 'insert into '|| vTabName ||' select * from employees where department_id = :nDept_id' using nDept_id;
delete from employees where department_id = nDept_id;
exception when others then
dbms_output.put_line(sqlerrm);
end;
/

Select Query Column name based on Table name

I have like thousands tables, each of them will have their own unique key(s) columns. I want to select the keys based on the table name in a single query. Its always the second column in the table if it helps.
I want something like
select c_name from t_name
where c_name (is)
(
select column_name as c_name
from Dba_tab_Columns
where table_name = t_name
and column_name like '%name' --->>>(((or column_id =2)))
)
I know the t_name but I need a single query to select column name based on table_name.
So let say if I say select c_name from Animals, it should give me list of all animals and if I say select c_name from Cars, it should give me a list of avilable cars.
You cannot do this in pure SQL, you'll need a table function. Here's a way:
create or replace type tvc as table of varchar2(128);
/
create or replace function return_col (tname user_tables.table_name%type) return tvc pipelined
as
c_statement varchar2(400);
get_data sys_refcursor;
out_d varchar2(128);
begin
for gettnames_and_cols in (select c.column_name
from user_cons_columns c, user_constraints uc
where constraint_type in ('P','U') and uc.table_name=c.table_name and c.table_name=upper(tname)) loop
c_statement:='select '||gettnames_and_cols.column_name||' as output_col from '||tname;
open get_data for c_statement;
while true loop
fetch get_data into out_d;
exit when get_data%notfound;
pipe row(out_d);
end loop;
close get_data;
end loop;
return;
end;
/
Thing is that this just gives the data, with no idea what's the column_name or from which table the data comes. You can modify the PL/SQL code to add this info. Also, this assumes that the data will be returned as VARCHAR2(128), you may need to adapt this to your needs. You use this table function as follows:
select *
from table (return_col('your_table_name'));

How many rows inserted into table by create table statement

Is there a way to count how many rows inserted into table by
Create table tbl1 as select * from tbl2;
statement which performed from PL\SQL function (execute immediate)?
When I'm using SQL%ROWCOUNT the result is 1.
Thanks.
You can try this. As mentioned in my comment you need to do it as followed. Remember that you need again to use Execute immediate else you get an issue that tab1 is undefined.
DECLARE
vsql VARCHAR2 (200);
cnt NUMBER;
BEGIN
vsql := 'create table tbl1 as select * from employee';
EXECUTE IMMEDIATE vsql;
vsql := 'select count(1) from tbl1';
EXECUTE IMMEDIATE vsql INTO cnt;
DBMS_OUTPUT.put_line (cnt);
END;
You can do one thing. You can first create an empty table tbl1 from tbl2. Then insert data using SELECT and then use- SQL%ROWCOUNT.
CREATE TABLE tbl1 AS SELECT * FROM tbl2 WHERE 1=2;
INSERT INTO tbl1 SELECT * FROM tbl2;
DBMS_OUTPUT.PUT_LINE ('No. of rows inserted in TBL2 from TBL1 = ' || SQL%ROWCOUNT);

For Loop in Oracle / Toad

I am new to Oracle and PL/SQL and am trying to do the following.
I am returning the column names from a table name that is stored in a variable
variable v_table varchar2(100)
begin
select 'mytable' into :v_table from dual;
end;
select column_name from all_tab_columns where table_name = :v_table
This returns a rowset
column_name
colname1
colname2
colname3
I would like to loop through the returned rowset and get some stats for each column.
select count distinct(colname1), min(colname1), max(colname1)
from :v_table
group by min(colname1), max(colname1)
However I cannot figure out how to loop through this rowset.
By using below you can display column names of a table and append your sql query as per your requirement...
declare
v_table varchar2(100):='TABLE_NAME';
TYPE NT_VAR1 IS TABLE OF VARCHAR2(30);
TYP_NT NT_VAR1;
begin
select column_name BULK COLLECT INTO TYP_NT from all_tab_columns where table_name =v_table
order by column_id;
FOR I IN 1..TYP_NT.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('COLUMN '||I||': '||TYP_NT(I));
END LOOP;
end;
Note: You should run select query dynamically means with the use of execute immediate why because you are passing table_name at run time.
Edit
After editing your query in for loop it will look like below.
declare
v_table varchar2(100):='TABLE_NAME';
TYPE NT_VAR1 IS TABLE OF VARCHAR2(30);
TYP_NT NT_VAR1;
var2 varchar2(2000);
var3 varchar2(2000);
begin
select column_name BULK COLLECT INTO TYP_NT from all_tab_columns where table_name =v_table
order by column_id;
FOR I IN 1..TYP_NT.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('COLUMN '||I||': '||TYP_NT(I));
EXECUTE IMMEDIATE 'SELECT to_char(min('||TYP_NT(I)||')),to_char(max('||TYP_NT(I)||')) from '||v_table into var2,var3;
dbms_output.put_line(var2||' '||var3);
END LOOP;
end;
Note: Find the max data length of a column present in your table and assign same data type to var2 and var3 variables.

If I drop a table and the table doesn't exist, I get an error

I need to drop a table and make a new one. If I drop the table and the table doesn't exist, I get an error
How can I check if the table exists?
I'm working on Oracle 11g
Thanks in advance.
You could do something like this:
DECLARE v_exist PLS_INTEGER;
BEGIN
SELECT COUNT(*) INTO v_exist
FROM user_tables
WHERE table_name = 'YOURTABLEHERE';
IF v_exist = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE YOURTABLEHERE';
END IF;
DECLARE
eTABLE_OR_VIEW_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(eTABLE_OR_VIEW_DOES_NOT_EXIST, -942);
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SCHEMA.WHATEVER';
EXCEPTION
WHEN eTABLE_OR_VIEW_DOES_NOT_EXIST THEN
NULL;
END;
Share and enjoy.
something like
select count(*) from user_tables
where table_name= :table name
or
select count(*) from dba_tables
where owner = :table owner
and table_name = :table name
or a heavy-handed alternative:
begin execute immediate 'drop table table_name';
exception when others then null;
end;
I have been using the following procedure to take care of this:
create or replace procedure drop_table_if_exists ( p_table_name varchar2 )
is
it_exist number;
begin
select count(*)
into it_exists
from user_tables
where table_name = p_table_name
;
if it_exists >= 1 then
execute immediate 'drop table '||p_table_name;
end if;
end;
/
exec drop_table_if_exists ( 'TABLE_TO_DROP' );

Resources