Select records from table where table name come from another table - sql

We generate tables dynamically Eg. Table T_1, T_2, T_3, etc & we can get that table names from another table by following query.
SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC';
Now I want to get records from this retrieved table name. What can I do ?
I'm doing like following but that's not working :
SELECT * FROM (SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC')
FYI : I'm hitting two individual queries as of now though I want to eliminate one and I can not follow cursor/procedure approach due to some limitations.

A procedure which utilizes refcursor seems to be the most appropriate to me. Here's an example:
SQL> -- creating test case (your T_NAMES table and T_1 which looks like Scott's DEPT)
SQL> create table t_names (t_id number, t_key varchar2(3));
Table created.
SQL> insert into t_names values (1, 'ABC');
1 row created.
SQL> create table t_1 as select * from dept;
Table created.
SQL> -- a procedure; accepts KEY and returns refcursor
SQL> create or replace procedure p_test
2 (par_key in varchar2, par_out out sys_refcursor)
3 as
4 l_t_name varchar2(30);
5 begin
6 select 'T_' || t_id
7 into l_t_name
8 from t_names
9 where t_key = par_key;
10
11 open par_out for 'select * from ' || l_t_name;
12 end;
13 /
Procedure created.
OK, let's test it:
SQL> var l_out refcursor
SQL> exec p_test('ABC', :l_out)
PL/SQL procedure successfully completed.
SQL> print l_out
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>

I could propose to you Dynamic SQL.
First of all, you need to create a cursor. The cursor will iterate by the dynamic tables. Then you could use dynamic SQL to create a query and then execute it.
So example:
https://livesql.oracle.com/apex/livesql/file/content_C81136WLRFYZF8ION6Q57GWE1.html - detailed cursor example.
https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm#i13057 - dynamic SQL in Oracle

Related

How can I get the table name in a Oracle trigger function?

How can I get the table name inside trigger function?
Something similar to TG_TABLE_NAME in Postgres, like this
Oracle 10g or above.
That's user_triggers view (if I understood the question correctly).
SQL> create table test (id number, name varchar2(20));
Table created.
SQL> create or replace trigger trg_test
2 before insert on test
3 for each row
4 begin
5 null;
6 end;
7 /
Trigger created.
SQL> select trigger_name, table_name from user_triggers;
TRIGGER_NAME TABLE_NAME
------------------------------ ------------------------------
TRG_TEST TEST --> this is the one I've just created
TRG_AIUD_EMP EMPLOYEES
SQL>

Create Auto Sequence text and number in oracle 11g

How I do create column ID with value JASG1?
I am only find example like this :
select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job
Although what you wrote probably works (if there's a sequence named MTJ_ID_SEQ, you have a privilege to select from it; the same goes for the TALEND_JOB table), I'd say that it isn't what you should use.
Here's why: I'll create a table and a sequence. Table will be pre-populated with some IDs (just to put something in there).
SQL> create sequence mtj_id_seq;
Sequence created.
SQL> create table talend_job as
2 select rownum id from dept;
Table created.
SQL> select * from talend_job;
ID
----------
1
2
3
4
OK; 4 rows so far. Now, run your SELECT:
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG1
JASG2
JASG3
JASG4
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG5
JASG6
JASG7
JASG8
SQL>
See? You didn't get only 1 JASGx value, but as many as number of rows in the TALEND_JOB table. If there was a million rows, you'd get a million JASGx rows as well.
Therefore, maybe you meant to use DUAL table instead? E.g.
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG9
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG10
SQL>
See? Only one value.
Also, notice that sequences will provide unique values, but you can't rely on them being gapless.
As you mentioned "how to create column ID" - one option is to use a trigger. Here's an example:
SQL> create table talend_job (id varchar2(20), name varchar2(20)
Table created.
SQL> create or replace trigger trg_bi_tj
2 before insert on talend_job
3 for each row
4 begin
5 :new.id := 'JASG' || mtj_id_seq.nextval;
6 end;
7 /
Trigger created.
Let's insert some names; IDs should be auto-populated by the trigger:
SQL> insert into talend_job (name) values ('littlefoot');
1 row created.
SQL> insert into talend_job (name) values ('Ishak');
1 row created.
SQL> select * From talend_job;
ID NAME
-------------------- --------------------
JASG11 littlefoot
JASG12 Ishak
SQL>
OK then; now you have some more info - read and think about it.
By the way, what is the "compiler-errors" tag used for? Did you write any code and it failed? Perhaps you'd want to share it with us.

SQL Oracle, returning a table from a Function

I was trying create a function (maybe procedure will be better?) which return a table. Presently I have this:
CREATE OR REPLACE TYPE rowx AS OBJECT
(
nam1 VARCHAR2 (100),
nam2 VARCHAR2 (100)
);
/
CREATE OR REPLACE TYPE tablex
IS TABLE OF rowx;
/
CREATE OR REPLACE FUNCTION example(FS varchar2)
RETURN tablex
IS
tab tablex;
BEGIN
select y.ident as PARENT, x.ident as CHILD into tab
from relation2 rt
inner join plate x on rt.child = x.id
inner join plate y on rt.parent =y.id
where x.ident like 'string1' or y.ident like 'string2';
RETURN tab;
END;
After compilation above function I recive ORA-00947. Any tips?
Your query is selecting two scalar values, and trying to put them into a table of an object type. That type has two fields, but there is no automatic comversion. So you need to build the object explicitly, which you can do as part of the query.
You should also use a bulk query to populate your collection:
select rowx(y.ident, x.ident)
bulk collect into tab
from relation2 rt
...
Have a look at this example; does it help?
My TEST table represents your tables. This function returns a collection, which is then used in SELECT statement along with the TABLE operator.
SQL> create table test (nam1 varchar2(10), nam2 varchar2(10));
Table created.
SQL> insert into test values ('Little', 'Foot');
1 row created.
SQL> insert into test values ('Stack', 'Overflow');
1 row created.
SQL> create or replace type t_tf_row as object (nam1 varchar2(10), nam2 varchar2(10));
2 /
Type created.
SQL> create or replace type t_tf_tab is table of t_tf_row;
2 /
Type created.
SQL>
SQL> create or replace function get_tab_tf return t_tf_tab as
2 l_tab t_tf_tab := t_tf_tab();
3 begin
4 for cur_r in (select nam1, nam2 from test) loop
5 l_tab.extend;
6 l_tab(l_tab.last) := t_tf_row(cur_r.nam1, cur_r.nam2);
7 end loop;
8 return l_tab;
9 end;
10 /
Function created.
SQL>
SQL> select * From table(get_Tab_tf);
NAM1 NAM2
--------------------
Little Foot
Stack Overflow
SQL>

How to display first name in single line?

I'm learning oracle sql.
I'm just trying to display all the employees first name from 'Employee' table in single line with comma separation.
ex: john,alex,rosy
I'm using SQL*Plus for running the query.
You have to use some built in function like:
SYS_CONNECT_BY_PATH , ROW_NUMBER () OVER
Here is the solution
SQL>
SQL> create table test(id int, name varchar(10));
Table created
SQL> begin
2 insert into test values(1,'john');
3 insert into test values(2,'alex');
4 insert into test values(3,'rosy');
5 end;
6 /
PL/SQL procedure successfully completed
SQL> select listagg(name ,',') within group(order by id) result from test;
RESULT
--------------------------------------------------------------------------------
john,alex,rosy
SQL> drop table test purge;
Table dropped
SQL>

Executing an sql statement stored in a procedure parameter

I have a question about stored procedures in Oracle.
Below is the stored procedure and tables as it stands:
create table STORES
(
ID number,
NAME varchar2(100),
CITY varchar2(100),
EXPIRES DATE
)
insert into stores values(1, 'Store 1', 'City 1', sysdate);
insert into stores values(2, 'Store 2', 'City 1', sysdate);
insert into stores values(3, 'Store 3', 'City 2', sysdate);
create table CLOSED
(
ID number,
NAME varchar2(100),
CITY varchar2(100)
)
create or replace PROCEDURE
pr_TestProc(subQuery IN VARCHAR2)
IS
begin
insert into CLOSED (ID, NAME, CITY)
select ID, NAME, CITY
from STORES
where ID in (1, 2, 3);
end;
What I'd like to do is replace the "in" values with the subQuery passed in as a parameter.
So if I run the procedure like:
execute pr_TestProc('select ID from STORES where EXPIRES <= sysdate');
The query passed in should be executed as a subquery being run inside the procedure.
Something like:
insert into CLOSED (ID, NAME, CITY) select ID, NAME, CITY
from STORES
where ID in (execute(subQuery));
Obviously this doesn't work, but what would be the best way to achieve this, or is it even possible?
Thanks,
Brian
You can use dynamic SQL
create or replace PROCEDURE pr_TestProc(subQuery IN VARCHAR2)
IS
l_sql_stmt varchar2(1000);
begin
l_sql_stmt := 'insert into CLOSED (ID, NAME, CITY) ' ||
' select ID, NAME, CITY ' ||
' from STORES ' ||
' where id in (' || subquery || ')';
dbms_output.put_line( l_sql_stmt );
EXECUTE IMMEDIATE l_sql_stmt;
end;
SQL> execute pr_TestProc('select ID from STORES where EXPIRES <= sysdate');
PL/SQL procedure successfully completed.
SQL> column name format a20
SQL> column city format a20
SQL> select * from closed;
ID NAME CITY
---------- -------------------- --------------------
1 Store 1 City 1
2 Store 2 City 1
3 Store 3 City 2
If you are calling this procedure rarely in a system that is relatively idle, that will probably work acceptably well. If you are calling it frequently with different subqueries, however, you are going to generate a ton of non-sharable SQL statements. That will force Oracle to do a lot of hard parsing. It will also flood your shared pool with non-sharable SQL statements, likely forcing out plans that you want to be cached, forcing more hard parsing when those SQL statements are then executed again. And if you do it fast enough, you're likely to end up getting errors (or causing other processes to get errors) that Oracle couldn't allocate enough memory in the shared pool for a particular query. Plus, dynamic SQL is harder to write, harder to debug, vulnerable to SQL injection attacks, etc. so it generally makes the system harder to deal with.
A more elegant solution would be to pass in a collection rather than a subquery would be to pass in a collection
SQL> create type id_coll
2 as table of number;
3 /
Type created.
SQL> ed
Wrote file afiedt.buf
1 create or replace PROCEDURE pr_TestProc( p_ids IN id_coll)
2 is
3 begin
4 insert into CLOSED (ID, NAME, CITY)
5 select ID, NAME, CITY
6 from STORES
7 where ID in (select column_value
8 from table( p_ids ) );
9* end;
SQL> /
Procedure created.
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_ids id_coll;
3 begin
4 select id
5 bulk collect into l_ids
6 from stores
7 where expires <= sysdate;
8 pr_TestProc( l_ids );
9* end;
SQL> /
PL/SQL procedure successfully completed.
SQL> select * from closed;
ID NAME CITY
---------- -------------------- --------------------
1 Store 1 City 1
2 Store 2 City 1
3 Store 3 City 2
Maybe you dont need to pass the query into the stored procedure. Just call the stored procedure with the query as a parameter.
create or replace PROCEDURE
pr_TestProc(listOfIds_IN IN integer)
IS
begin
ids integer := listOfIds_IN;
insert into CLOSED (ID, NAME, CITY)
select ID, NAME, CITY from STORES where ID in (ids );
end;
Call the stored procedure like this:
pr_TestProc(SELECT id FROM Table WHERE condition)