Select query for dynamic Table Name in oracle SQL - oracle

I tried the following code:
declare
selectedtable varchar2(50);
tablename varchar2(50);
begin
selectedtable := 'ATABLE';
SELECT table_name into tablename FROM all_tables where table_name = selectedtable;
select * from tablename;
end;
But I got "Table or View does not exist."

It can't work that way because
tablename is unknown; Oracle "thinks" it is a table name (real table name, available to you)
select * from ... is invalid in PL/SQL - it requires an INTO clause. Moreover, unless it returns exactly one row, you'll get either no_data_found or too_many_rows error
What you could do, is to use tablename variable in a ref cursor.
Let's presume that tablename now contains table name retrieved from all_tables; though, why would you want to do that? You already have that name in selectedtable variable ... Also, if there are two (or more) tables that share that name - as you're selecting from all_tables - you'll get too_many_rows error - hence, I used the distinct keyword. If there's no such table, your query will return no_data_found you didn't handle. But OK, let's suppose that table in selectedtable exists.
Then:
SQL> declare
2 selectedtable varchar2(50);
3 tablename varchar2(50);
4 --
5 -- Some new local variables
6 rc sys_refcursor;
7 l_deptno number;
8 l_dname varchar2(20);
9 l_loc varchar2(20);
10 begin
11 selectedtable := 'DEPT';
12 SELECT distinct table_name into tablename FROM all_tables where table_name = selectedtable;
13
14 open rc for 'select * from ' || tablename;
15 loop
16 fetch rc into l_deptno, l_dname, l_loc;
17 exit when rc%notfound;
18 dbms_output.put_line('Fetched: ' || l_deptno ||', '|| l_dname ||', '|| l_loc);
19 end loop;
20 end;
21 /
Fetched: 10, ACCOUNTING, NEW YORK
Fetched: 20, RESEARCH, DALLAS
Fetched: 30, SALES, CHICAGO
Fetched: 40, OPERATIONS, BOSTON
PL/SQL procedure successfully completed.
SQL>

Related

executing select statement stored in table column by replacing variable value dynamically

I have simple PL/SQL block with below code
declare
rule1 varchar2(100 char);
begin
for i in (select table_name from all_tables where table_owner='EqEDI') loop
execute immediate 'select rule_stmt from rulebook ' into rule1 ;
execute immediate rule1 into result;
dbms_output.put_line('Result is '||result);
end loop;
end;
the rule statement stored in table rulebook is :
"'select count(1) from '|| tablename"
I want this above statement to be executed for all tables present for given owner
but while executing, it does not replace tablename in query with actual tables.
How can I achieve this with simple PL/SQL block.
Regards
rulebook table's contents is kind of wrong. Not that you can NOT do it the way you stored select statement into it - it is just impractical as you have to remove single quotes, remove tablename (as you can't even bind it, but concatenate what cursor returned) ... too much unnecessary jobs to be done.
Also, check all_tables and names of its columns - there's no table_owner, just owner.
Therefore, I'd suggest you to store such a statement:
SQL> SELECT * FROM rulebook;
RULE_STMT
--------------------------------------------------------------------------------
select count(*) from
Fix your PL/SQL script:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 rule1 VARCHAR2 (100 CHAR);
3 l_str VARCHAR2 (100);
4 result NUMBER;
5 BEGIN
6 FOR i IN (SELECT table_name
7 FROM all_tables
8 WHERE owner = 'SCOTT'
9 AND table_name = 'EMP')
10 LOOP
11 EXECUTE IMMEDIATE 'select rule_stmt from rulebook '
12 INTO rule1;
13
14 l_str := rule1 || i.table_name;
15
16 EXECUTE IMMEDIATE l_str
17 INTO result;
18
19 DBMS_OUTPUT.put_line ('Result is ' || result);
20 END LOOP;
21 END;
22 /
Result is 14
PL/SQL procedure successfully completed.
SQL>

how to take second column if first column not found in table in oracle DB

I'm expecting to write a query which takes second column if first column not found in table in oracle DB. In my case 'name' column is not present in table 'employees'
NOTE : I'm using reference cursor
I tried below,
query1:='select id or name,age from employees';
when I execute above statement, getting error
ORA-00904 "name": invalid identifier
ORA-06512 : at "employees", line 21
Explicitly, I don't think you can (as you saw).
Though, you can select * from employees and it'll work:
SQL> declare
2 l_rc sys_refcursor;
3 l_row dept%rowtype;
4 begin
5 open l_rc for select * from dept;
6 fetch l_rc into l_row;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL>
Alternatively, did you consider creating a select statement dynamically, by querying user_tab_columns? Something like this:
SQL> declare
2 l_str varchar2(500);
3 l_rc sys_refcursor;
4 begin
5 for cur_r in (select column_name from user_tab_columns
6 where table_name = 'DEPT'
7 )
8 loop
9 l_str := l_str || ', '|| cur_r.column_name;
10 end loop;
11
12 l_str := 'select ' || ltrim(l_str, ', ') || ' from dept';
13
14 dbms_output.put_line(l_str);
15
16 open l_rc for l_str;
17 end;
18 /
select DEPTNO, DNAME, LOC from dept --> this is the SELECT statement
PL/SQL procedure successfully completed.
SQL>

Pass PL/SQL parameter as SCHEMA NAME

I'm trying to send variable schema name to cursor via procedure input
Here is my lame try, but you can see what I want to do:
CREATE OR REPLACE PROCEDURE HOUSEKEEPING
(SCHEMANAME in varchar2)
IS
CURSOR data_instances IS select table_name
from SCHEMANAME.table_name where TYPE='PERMANENT' and rownum<200 ;
BEGIN
DBMS_OUTPUT.PUT_LINE(SCHEMANAME);
END;
/
it throws expected
PL/SQL: ORA-00942: table or view does not exist
is there lawful way to make schema name work as variable? thanks
There is a way; you'll need some kind of dynamic SQL because you can't use schema (or object) names like that. For example, you could use refcursor instead.
Sample table:
SQL> create table table_name as
2 select 'EMP' table_name, 'PERMANENT' type from dual union all
3 select 'DEPT' , 'TEMPORARY' from dual union all
4 select 'BONUS' , 'PERMANENT' from dual;
Table created.
Procedure; note the way I composed SELECT statement first (so that I could display it and check whether it is correct), and then used it in OPEN. Loop is here to ... well, loop through the cursor. I'm just displaying table names I found - you'd probably do something smarter.
SQL> create or replace procedure housekeeping (par_schemaname in varchar2)
2 is
3 l_str varchar2(500);
4 l_rc sys_refcursor;
5 l_table_name varchar2(30);
6 begin
7 l_str := 'select table_name from ' ||
8 dbms_assert.schema_name(upper(par_schemaname)) ||
9 '.table_name where type = ''PERMANENT'' and rownum < 200';
10 open l_rc for l_str;
11
12 loop
13 fetch l_rc into l_table_name;
14 exit when l_rc%notfound;
15
16 dbms_output.put_line(l_table_name);
17 end loop;
18 close l_rc;
19 end;
20 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec housekeeping('SCOTT');
EMP
BONUS
PL/SQL procedure successfully completed.
SQL>

Check if both column and table exist and run queries based on the result

I am trying to run some SQL queries on Oracle database, but before running the query I need to check if both table and column exists. If table exists and column does not exist, then run another query:
if table `testtable` exists and if table has column `testcolumn`
Run a SQL which returns the result
else if table `testtable` exists but column `testcolumn` not present
Run a different sql which also returns the result
else
print some defined string
You can use:
DECLARE
nCount NUMBER;
BEGIN
SELECT COUNT(*)
INTO nCount
FROM USER_TAB_COLS
WHERE TABLE_NAME = 'TESTTABLE' AND
COLUMN_NAME = 'TESTCOLUMN';
IF nCount > 0 THEN
-- Run a SQL which returns the result
ELSE
SELECT COUNT(*)
FROM USER_TABLES
WHERE TABLE_NAME = 'TESTTABLE';
IF nCount > 0 THEN
Run a different sql which also returns the result
ELSE
print some defined string
END;
You'll have to add code to run whatever SQL you're trying to run, and to print whatever message you need.
Best of luck.
Here's one option - check contents of USER_TAB_COLUMNS and - depending on what you find - use refcursor in order to return the result.
SQL> create or replace function f_test
2 return sys_refcursor
3 is
4 l_cnt number;
5 cur_r sys_refcursor;
6 begin
7 -- 1st test - this one fails
8 select count(*)
9 into l_cnt
10 from user_tab_columns
11 where table_name = 'EMP'
12 and column_name = 'DOES_NOT_EXIST';
13
14 if l_cnt > 0 then
15 open cur_r for select ename, job, sal from emp;
16 end if;
17
18 -- 2nd test - this one is OK
19 select count(*)
20 into l_cnt
21 from user_tab_columns
22 where table_name = 'DEPT'
23 and column_name = 'DEPTNO';
24
25 if l_cnt > 0 then
26 open cur_r for select dname, loc from dept;
27 end if;
28
29 return cur_r;
30 end;
31 /
Function created.
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DNAME LOC
-------------- -------------
ACCOUNTING NEW YORK
RESEARCH DALLAS
SALES CHICAGO
OPERATIONS BOSTON
SQL>
It has to be some kind of a dynamic code because you can't just write a static SELECT statement that selects non-existent columns as you'd get ORA-00904: "DOES_NOT_EXIST": invalid identifier error.

Using SELECT within SELECT statement in ORACLE

I have a table name SAMPLETABLE this has the tablenames of the tables I require in column TABLENAMES. Lets say the tablenames are TABLEA, TABLEB and TABLEC.
On query
SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1
I get the output the output of TABLENAMES column with TABLEA value.
My problem is, now I want to use this selected value in a select statement. That is,
SELECT * FROM (SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1)
My idea is that it'd return the contents of TABLEA because when the nested SELECT returns TABLEA, the outer SELECT should capture and display it.
On the contrary, I get the output only of the inner statement, that is,
SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1
and
SELECT * FROM (SELECT TABLENAMES FROM SAMPLETABLE WHERE ROWNUM = 1)
return the same output.
I want the first SELECT statement to fetch the returned value of second SELECT and display the table. They above query doesn't do that, so how do I do it? And what is wrong with my idea?
I am on Oracle 10g, any help appreciated.
As table name is not known at compile time you need to use dynamic SQL(execute immediate, native dynamic SQL, for instance) to be able to select from a table, name of which is stored as a string literal - you cannot accomplish it with static SQL
Here is an example:
-- table which contains names of other tables
-- in the table_name column
SQL> create table Table_Names as
2 select 'employees' as table_name
3 from dual
4 ;
Table created
SQL> set serveroutput on;
-- example of an anonymous PL/SQL block
-- where native dynamic SQL (execute immediate statement)
-- is used to execute a dynamically formed select statement
SQL> declare
2 type T_record is record( -- example of record for fetched data
3 f_name varchar2(123),
4 l_name varchar2(123)
5 );
6
7 l_table_name varchar2(123); -- variable that will contain table name
8 l_select varchar2(201);
9 l_record T_Record; -- record we are going to fetch data into
10 begin
11 select table_name
12 into l_table_name -- querying a name of a table
13 from table_names -- and storing it in the l_table_name variable
14 where rownum = 1;
15
16 l_select := 'select first_name, last_name from ' ||
17 dbms_assert.simple_sql_name(l_table_name) ||
18 ' where rownum = 1'; -- forming a query
19
20 execute immediate l_select -- executing the query
21 into l_record;
22 -- simple output of data just for the sake of demonstration
23 dbms_output.put_line('First_name: ' || l_record.f_name || chr(10) ||
24 'Last name: ' || l_record.l_name);
25 exception
26 when no_data_found
27 then dbms_output.put_line('Nothing is found');
28 end;
29 /
First_name: Steven
Last name: King
PL/SQL procedure successfully completed
As a second option you could use weakly typed cursors - refcursors to execute a dynamically formed select statement:
SQL> variable refcur refcursor;
SQL> declare
2 l_table_name varchar2(123);
3 l_select varchar2(201);
4 begin
5 select table_name
6 into l_table_name
7 from table_names
8 where rownum = 1;
9
10 l_select := 'select first_name, last_name from ' ||
11 dbms_assert.simple_sql_name(l_table_name) ||
12 ' where rownum = 1';
13
14 open :refcur
15 for l_select;
16
17 exception
18 when no_data_found
19 then dbms_output.put_line('Nothing is found');
20 end;
21 /
PL/SQL procedure successfully completed.
SQL> print refcur;
FIRST_NAME LAST_NAME
-------------------- -------------------------
Steven King
SQL> spool off;
Find out more about cursors and cursor variables
You can do this with help of dynamic sql. Since the table name is obtained during run time you have to frame the query dynamically and run it.
Declare
Tab_Name Varchar2(30);
Begin
SELECT TABLENAMES into Tab_Name FROM SAMPLETABLE WHERE ROWNUM = 1;
Execute Immediate 'Select * into (Collection Variable) from ' || Tab_Name;
End
/
I just gave it as example. You declare a variable to get the data out or something else as you need. But when you try to use execute immediate with input parameter read about sql injection and then write your code.

Resources